Libraries and functions

Load the libraries we will need for the analysis.

Load our functions.

#This function calculates PTS or PAS in the case of microsatellites.
pairwiseType <- function(x){
    x <- t(x)
    mm <- as(x, "dgCMatrix")
    d <- tcrossprod(mm)
    denom <- matrix(rep(rowSums(x), ncol(d)), ncol = ncol(d), byrow = FALSE)
    denom <- denom + t(denom)
    return(as.matrix(2*d/denom))
}

#This function calculates Sij and Sji (i.e., directional PTS) as in He et al 2018.
geneticSimilarity <- function(mat){
  newmat <- tcrossprod(mat > 0)
  newmat <- newmat/rowSums(mat > 0)
  return(newmat)  
}

#This function saves the PTS matrix values into a table for analysis purposes.
PTSmatrixToTable <- function(x){
  diag(x) <- NA
  x[upper.tri(x)] <- NA

  df <- data.frame(SampleID1 = rownames(x)[row(x)], SampleID2 = colnames(x)[col(x)], PTS_score = c(x))
  df <- na.omit(df)
  return(df)
}

#This function saves the Genetic Similarity matrix values into a table for analysis purposes. Note that there are two GS scores for every isolate pair (i.e. directional PTS)
GSmatrixToTable <- function(x){
  diag(x) <- NA

  df <- data.frame(SampleID1 = rownames(x)[row(x)], SampleID2 = colnames(x)[col(x)], GS_score = c(x))
  df <- na.omit(df)
  return(df)
}

#This function saves the Genetic Similarity matrix values into a table for analysis purposes. Note that for the varcode analysis we only include retrospective PTS and we want to include the diagonal for the *var*code comparisons (i.e. the 1).
GSmatrixToTable_VC <- function(x){
  x[upper.tri(x)] <- NA
  df <- data.frame(SampleID1 = rownames(x)[row(x)], SampleID2 = colnames(x)[col(x)], GS_score = c(x))
  df <- na.omit(df)
  return(df)
}

Load data

ups <- fread("data/ecuador_ups_classification_final.csv", data.table = F, )
binary_all <- fread("data/ecuador_SAm_binary_matrix_final.csv", data.table = F)
binary_ecu <- fread("data/ecuador_binary_matrix_final.csv", data.table = F)
microsat_ecu <- fread("data/ecuador_binary_microsat_final.csv", data.table = F)
ecu_epi <- fread("data/ecuador_epi.csv", data.table = F)
outbreak_metadata <- read.csv("data/ecuador_varcode1_47types_metadata.csv")

Make matrices

matrix_all <- binary_all
rownames(matrix_all) <- matrix_all$DBLa_type
matrix_all <- matrix_all[, -1]
matrix_all <- as.matrix(matrix_all)

ecu_matrix <- binary_ecu 
rownames(ecu_matrix) <- ecu_matrix$DBLa_type
ecu_matrix <- ecu_matrix[, -1]
ecu_matrix <- as.matrix(ecu_matrix)

DBLα sampling depth

There were a total of 195 DBLα types and 58 isolates in Ecuador.

How well have we sampled the var diversity in Ecuador?

ecu_curve <- specaccum(t(ecu_matrix), method = "rarefaction")
plot(ecu_curve, xvar = "individuals", ci.type = "polygon", xlab = "Number of DBLα sequences sampled in Ecuador", ylab = "Number of DBLα types identified in Ecuador")

#save this via Rstudio

How well have we sampled the var diversity in South America?

There were a total of 543 DBLα types and 186 isolates in South America.

SAm_curve <- specaccum(t(matrix_all), method = "rarefaction")
plot(SAm_curve, xvar = "individuals", ci.type = "polygon", xlab = "Number of DBLα sequences sampled in South America", ylab = "Number of DBLα types identified in South America")

##save this via Rstudio

Applying the varcode to examine transmission patterns in Ecuador

Genetic similarity: calculate directional PTS (retrospectively)

Because we are interested in looking at PTS or genetic similarity of parasites retrospecively, i.e. what happens after the outbreak, we will only examine pairwise comparisons of isolates retrospectively. This means that we will compare isolates “backwards” to identify how similar they are to the outbreak clone, or to anything else circulating before its identification.

genSim_ecu <- geneticSimilarity(t(ecu_matrix))
genSim_ecu[upper.tri(genSim_ecu)] <- NA
GStable_ecu <- GSmatrixToTable(genSim_ecu) 

Microsatellites: PAS

Here we will perform an analysis of the microsatellite PAS for every sample pair.

Note that for the PAS comparisons we actually don’t need the GS directional PTS for the majority of comparisons because the denominator is the same - however, we do have N=2 isolates with 6 alleles (i.e. 1 allele missing) and N=1 isolate with 5 alleles (i.e. 2 missing alleles), so will still calculate GS.

microsat_ecu <- microsat_ecu %>% filter(SampleID %in% ecu_epi$SampleID) %>% 
                                       column_to_rownames("SampleID") %>% 
                                       select(-one_of(c("MS_TA11", "MS_24901", "MS_C2M341", "MS_C3M691")))

microsat_PAS <- geneticSimilarity(microsat_ecu)
microsat_PAS[upper.tri(microsat_PAS)] <- NA
PAStable_ecuMS <- GSmatrixToTable(microsat_PAS)

PTS vs PAS

We can now compare the PTS and PAS values for each pairwise comparison (retrospectively) by matching the microsat pairwise comparisons SampleID1-SampleID2 with var enabling a direct comparison.

We are interested in looking at: how correlated are predictions of recombinants by var compared to MS?

GStable_ecu_varMS <- GStable_ecu %>% left_join(PAStable_ecuMS, by = c("SampleID1", "SampleID2"))
GStable_ecu_varMS <- GStable_ecu_varMS %>% rename_at("GS_score.x", ~"PTS_score") %>% 
                                           rename_at("GS_score.y", ~"PAS_score") 
                                     
correlation_plot <- GStable_ecu_varMS %>%
   ggplot(aes(x = PTS_score, y = PAS_score)) + 
      geom_jitter(shape = 21, color = "black", size = 2) +
      #stat_smooth_func(geom = "text", method = "lm", hjust = 0, parse = T) +
      geom_smooth(method = "lm", se = T, color = "darkgrey") +
      scale_y_continuous(breaks = seq(0, 1, by = 0.25)) + 
      theme_cowplot() +
      ylab(expression(paste("P"["AS"], " score"))) +
      xlab(expression(paste("P"["TS"], " score"))) +
      background_grid(major = "xy", minor = "none") 

cor.test(GStable_ecu_varMS$PTS_score, GStable_ecu_varMS$PAS_score, method = c("pearson"))

    Pearson's product-moment correlation

data:  GStable_ecu_varMS$PTS_score and GStable_ecu_varMS$PAS_score
t = 47.037, df = 1651, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.7353627 0.7766243
sample estimates:
      cor 
0.7567462 
save_plot("viz/correlation_PTSvPAS.png", correlation_plot, base_width = 8, base_height = 6)
correlation_plot

There were a total of 72 (14%) out of 541 pairwise comparisons where PAS=1 but PTS ≤0.50.

There were a total of 307 (25%) out of 1232 pairwise comparisons where PAS>0.50 but PTS ≤0.50.

Network Analysis: var

Visualizing genetic similarity network (PTS) using tidygraph/ggraph

Now we want to examine the relationships among repertoires by visualizing the retrospective PTS values in a network.

For future reference I am building the network by following the guidelines from this tutorial) and this tutorial. I will build the network using gg syntax (i.e. similar to ggplot syntax) using the packages ggraph and tidygraph.

First we need to save our data in the proper format to build the network. The GStable_ecu becomes our edges dataset, and the epi data becomes our nodes dataset. Note: make sure to use the following code to create the edges (i.e. assigning id), if not the PTS edges between isolates may be wrong. This way we ensure that the id.x and id.y of each edge corresponds to their actual SampleID in the nodes dataset.

ecu_edges <- GStable_ecu %>% left_join(ecu_epi, by = c("SampleID1" = "SampleID")) %>% rename(id.x = id)
ecu_edges <- ecu_edges %>% left_join(ecu_epi, by = c("SampleID2" = "SampleID")) %>% rename(id.y = id)
ecu_edges <- ecu_edges %>% select(id.x, id.y, GS_score)

ecu_tidy <- tbl_graph(nodes = ecu_epi, edges = ecu_edges, directed = T)

The tibble tidy_graph object consists of both edges and nodes, either of which can be activated depending on what we need to do.

Defining varcodes (PTS >= 0.9)

varcode_list <- ecu_epi %>% select(SampleID, varcode)
varcode_list$SampleID <- as.factor(varcode_list$SampleID)
varcode_list$varcode <- as.factor(varcode_list$varcode)
varcode_list <- varcode_list %>% column_to_rownames("SampleID")
varcode_colors <- list(varcode = c("varcode1" = "#fb9a99", "varcode2" = "#e538a9","varcode3" = "#48B24F", "varcode4" = "#30d5c8", "varcode5" = "#E4B031", "varcode6" = "#3090d5", "varcode7" = "#CAD93F", "varcode8" = "#9ac4b3", "varcode9" = "#a880bb"))

ecu_varcodes_network <- ecu_tidy %>% activate(edges) %>% filter(GS_score >= 0.9) %>% 
  ggraph(layout = "fr") + 
  geom_edge_link(color = "darkgrey", alpha = 0.5) + 
  geom_node_point(aes(fill = varcode), shape = 21, color = "black", size = 4) +
  #geom_node_text(aes(label = SampleID), repel = TRUE) +
  labs(edge_width = "SampleID",
       fill = "") +
  scale_fill_manual(values = varcode_colors$varcode, labels = c("varcode1 (N=36)", "varcode2 (N=3)", "varcode3 (N=3)", "varcode4 (N=1)", "varcode5 (N=1)", "varcode6 (N=3)", "varcode7 (N=8)", "varcode8 (N=2)", "varcode9 (N=1)")) +
  theme_graph()

save_plot("viz/ecuador_varcode_network.png", ecu_varcodes_network, base_width = 8, base_height = 6)
ecu_varcodes_network

We identify 9 varcodes in Ecuador. Note: ECPf004 and ECPf011 are undersampled, and belong to varcode1. The number of isolates grouped in each varcode is:
varcode n
varcode1 36
varcode2 3
varcode3 3
varcode4 1
varcode5 1
varcode6 3
varcode7 8
varcode8 2
varcode9 1

How many varcodes were there in each timepoint?

timepoints <- c("2013", "2014", "2015")
totalnum_varcodes <- c("3", "8", "4")
varcodes_bytime <- data.frame(timepoints, totalnum_varcodes)
The number of varcodes identified in each timepoint was as follows:
timepoints totalnum_varcodes
2013 3
2014 8
2015 4

.

How do varcodes persist in time?

varcode <- c("varcode1", "varcode2", "varcode3", "varcode6", "varcode7", "varcode8", "varcode4", "varcode5", "varcode9")
vc2013 <- c(30, 2, 1, NA, NA, NA, NA, NA, NA)
vc2014 <- c(4, 1, 2, 2, 6, 2, 1, 1, NA)
vc2015 <- c(2, NA, NA, 1, 2, NA, NA, NA, 1)
varcodes_temporal <- data.frame(varcode, vc2013, vc2014, vc2015)
varcodes_temporal <- varcodes_temporal %>% rename_at("vc2013", ~"2013") %>% rename_at("vc2014", ~"2014") %>% rename_at("vc2015", ~"2015")

varcodes_timeline <- varcodes_temporal %>% 
  melt(id.var = "varcode") %>% 
  rename_at("variable", ~"Year") %>% 
  rename_at("value", ~"Frequency") %>% 
  mutate(varcode = factor(varcode, levels = c("varcode9", "varcode8", "varcode7", "varcode6", "varcode5", "varcode4", "varcode3", "varcode2", "varcode1"))) %>% 
  ggplot(aes(Year, factor(varcode))) + 
      geom_point(aes(size = Frequency, color = varcode)) +
      geom_text(aes(label = Frequency), size = 2.5, vjust = 1.5, hjust = -1) +
      scale_size_continuous(name = "Number of Pf isolates",
             breaks = c(1, 10, 30),
             labels = c("1", "10", "30")) +
      scale_color_manual(values = varcode_colors$varcode, labels = varcode_list) +
      annotate("segment", x = 1, xend = 3, y = 9, yend = 9, colour = "#fb9a99") +
      annotate("segment", x = 1, xend = 2, y = 8, yend = 8, colour = "#e538a9") +
      annotate("segment", x = 1, xend = 2, y = 7, yend = 7, colour = "#48B24F") +
      annotate("segment", x = 2, xend = 3, y = 4, yend = 4, colour = "#3090d5") +
      annotate("segment", x = 2, xend = 3, y = 3, yend = 3, colour = "#CAD93F") +  
      ylab("") +
      theme_bw() 

save_plot("viz/varcodes_timeline.png", varcodes_timeline)
varcodes_timeline

Duration of varcode persistence

Now we can calculate the average days a varcode persisted.

ecu_epi$DateCollected <- as.Date(ecu_epi$DateCollected)

#ecu_epi %>% filter(SampleID == "ECPf003" | SampleID == "ECPf076") %>% select(varcode, DateCollected) 

vc1_duration <- data.frame(varcode = "varcode1", FirstID = subset(ecu_epi, SampleID == "ECPf003")$DateCollected, LastID = subset(ecu_epi, SampleID == "ECPf076")$DateCollected) 

vc2_duration <- data.frame(varcode = "varcode2", FirstID = subset(ecu_epi, SampleID == "ECPf024")$DateCollected, LastID = subset(ecu_epi, SampleID == "ECPf045")$DateCollected) 

vc3_duration <- data.frame(varcode = "varcode3", FirstID = subset(ecu_epi, SampleID == "ECPf035")$DateCollected, LastID = subset(ecu_epi, SampleID == "ECPf053")$DateCollected) 

vc6_duration <- data.frame(varcode = "varcode6", FirstID = subset(ecu_epi, SampleID == "ECPf051")$DateCollected, LastID = subset(ecu_epi, SampleID == "ECPf072")$DateCollected) 

vc7_duration <- data.frame(varcode = "varcode7", FirstID = subset(ecu_epi, SampleID == "ECPf056")$DateCollected, LastID = subset(ecu_epi, SampleID == "ECPf067")$DateCollected) 

vc_duration <- bind_rows(vc1_duration, vc2_duration, vc3_duration, vc6_duration, vc7_duration)

vc_duration <- vc_duration %>% mutate(duration_days = difftime(LastID, FirstID, units = c("days"))) %>% 
                               mutate(duration_yr = round(duration_days/365, 2)) %>% 
                               mutate(duration_months = round(duration_yr*12, 2))
The varcodes persisted for the following amount of time:
varcode FirstID LastID duration_days duration_yr duration_months
varcode1 2013-01-28 2015-05-01 823 days 2.25 days 27.00 days
varcode2 2013-07-15 2014-01-21 190 days 0.52 days 6.24 days
varcode3 2013-10-24 2014-05-28 216 days 0.59 days 7.08 days
varcode6 2014-03-13 2015-11-08 605 days 1.66 days 19.92 days
varcode7 2014-07-08 2015-01-19 195 days 0.53 days 6.36 days
The summary statistics for the duration of each varcode in days was:
min_days med_days avg_days max_days
190 days 216 days 405.8 days 823 days
The summary statistics for the duration of each varcode in months was:
min_months med_months avg_months max_months
6.24 days 7.08 days 13.32 days 27 days
The summary statistics for the duration of each varcode in years was:
min_yr med_yr avg_yr max_yr
0.52 days 0.59 days 1.11 days 2.25 days

Defining varcodes in San Lorenzo (PTS >= 0.9)

ecu_tidy %>% activate(nodes) %>% filter(LocationCode == "San Lorenzo, Esmeraldas") %>% 
  activate(edges) %>% filter(GS_score >= 0.9) %>% 
  ggraph(layout = "fr") + 
  geom_edge_link(color = "darkgrey", alpha = 0.5) + 
  geom_node_point(aes(fill = varcode), shape = 21, color = "black", size = 4) +
  #geom_node_text(aes(label = SampleID), repel = TRUE) +
  labs(edge_width = "SampleID",
       fill = "") +
  scale_fill_manual(values = varcode_colors$varcode) +
  theme_graph()

Identifying recombinants: transmission network varcodes (PTS >= 0.5)

ecuador_recombinants_network <- ecu_tidy %>% activate(edges) %>% filter(GS_score >= 0.5) %>% 
  ggraph(layout = "fr") + 
  geom_edge_link(color = "darkgrey", alpha = 0.5) + 
  geom_node_point(aes(fill = varcode), shape = 21, color = "black", size = 4) +
  scale_fill_manual(values = varcode_colors$varcode, labels = varcode_list) +
  #geom_node_text(aes(label = SampleID), repel = TRUE) +
  labs(edge_width = "SampleID") +
  theme_graph()

save_plot("viz/ecuador_recombinants_network.png", ecuador_recombinants_network, base_width = 8, base_height = 6)
ecuador_recombinants_network

Network analysis: microsatellites

ecuMSedges <- PAStable_ecuMS %>% left_join(ecu_epi, by = c("SampleID1" = "SampleID")) %>% rename(id.x = id)
ecuMSedges <- ecuMSedges %>% left_join(ecu_epi, by = c("SampleID2" = "SampleID")) %>% rename(id.y = id)
ecuMSedges <- ecuMSedges %>% select(id.x, id.y, GS_score)

ecuMS_tidy <- tbl_graph(nodes = ecu_epi, edges = ecuMSedges, directed = T)

Defining clones by MS

ecuador_MSclusters_network <- ecuMS_tidy %>% activate(edges) %>% filter(GS_score >= 0.90) %>% 
  ggraph(layout = "fr") + 
  geom_edge_link(color = "darkgrey", alpha = 0.5) + 
  geom_node_point(aes(fill = varcode), shape = 21, color = "black", size = 4) +
  scale_fill_manual(values = varcode_colors$varcode, labels = varcode_list) +
  #geom_node_text(aes(label = SampleID), repel = TRUE) +
  labs(edge_width = "SampleID") +
  theme_graph()

save_plot("viz/ecuador_MSclusters_network.png", ecuador_MSclusters_network, base_width = 8, base_height = 6)
ecuador_MSclusters_network

Defining clones by MS

Allowing for 1 allele diff

ecuador_MSclusters_network80 <- ecuMS_tidy %>% activate(edges) %>% filter(GS_score >= 0.80) %>% 
  ggraph(layout = "fr") + 
  geom_edge_link(color = "darkgrey", alpha = 0.5) + 
  geom_node_point(aes(fill = varcode), shape = 21, color = "black", size = 4) +
  scale_fill_manual(values = varcode_colors$varcode, labels = varcode_list) +
  #geom_node_text(aes(label = SampleID), repel = TRUE) +
  labs(edge_width = "SampleID") +
  theme_graph()

save_plot("viz/ecuador_MSclusters_network_PTS80.png", ecuador_MSclusters_network80, base_width = 8, base_height = 6)
ecuador_MSclusters_network80

MS clones supplementary figure

ecuador_MSclusters_supp <- ecuador_MSclusters_network + ecuador_MSclusters_network80 +
  plot_layout(guides = "collect") + plot_annotation(tag_levels = "a")
  
save_plot("viz/ecuador_MSclusters_networks_both.png", ecuador_MSclusters_supp, base_width = 12, base_height = 6)
ecuador_MSclusters_supp

Identifying recombinants by MS: transmission network

ecuador_MSrecomb_network <- ecuMS_tidy %>% activate(edges) %>% filter(GS_score >= 0.5) %>% 
  ggraph(layout = "fr") + 
  geom_edge_link(color = "darkgrey", alpha = 0.5) + 
  geom_node_point(aes(fill = varcode), shape = 21, color = "black", size = 4.5) +
  scale_fill_manual(values = varcode_colors$varcode, labels = varcode_list) +
  #geom_node_text(aes(label = SampleID), repel = TRUE) +
  labs(edge_width = "SampleID") +
  theme_graph()

save_plot("viz/ecuador_MSrecomb_network.png", ecuador_MSrecomb_network, base_width = 8, base_height = 6)
ecuador_MSrecomb_network

This very clearly shows that describing transmission dynamics using microsatellites is not sufficient to identify recent genetic exchanges and recent recombination/transmission events since everything is connected by MS. Since var genes are rapidly evovling compared to MS, they allow us to “track” recombination and transmission dynamics in space and time.

Clustering Analysis (heatmaps)

varcode heatmap clustered

###Trying to order the clusters by "year"
pheatmap(t(ecu_matrix), col = c("white", "black"),
         annotation_row = varcode_list, 
         annotation_colors = varcode_colors, 
         fontsize_row = 5, fontsize_col = 5, 
         cluster_rows = T, cluster_cols = F, 
         legend = F, 
         treeheight_col = 0, 
         show_colnames = F,
         show_rownames = F, 
         #filename = "viz/varcode_heatmap.png",
         width = 8, 
         height = 4)

Microsat heatmap

###Trying to order the clusters by "year"
pheatmap(microsat_ecu, col = c("white", "black"),
         annotation_row = varcode_list, 
         annotation_colors = varcode_colors, 
         fontsize_row = 5, fontsize_col = 5, 
         cluster_rows = T, cluster_cols = F, 
         legend = F, 
         treeheight_col = 0, 
         show_colnames = F,
         show_rownames = F,
         #filename = "viz/microsat_heatmap.png",
         width = 8, 
         height = 4)

Spatial Analysis

Map of Ecuador

register_google(key = "INSERT_KEY")

geocode("Ecuador")
map <- get_googlemap(center = "Ecuador", zoom = 7, maptype = "terrain", style = "feature:poi.business|visibility:off&style=feature:road|element:labels.icon|visibility:off&style=feature:transit|visibility:off") 
ecu_map <- ggmap(map) + xlab("Longitude") + ylab("Latitude")
ecu_map <- ecu_map + scalebar(x.min = -77, x.max = -75,
                              y.min = -4.8, y.max = -4.7,
                              dist = 100, 
                              dist_unit = "km", 
                              transform = T, 
                              model = "WGS84",
                              #st.bottom = F,
                              st.dist = 1,
                              height = 1, 
                              st.size = 3) +
                              annotation_north_arrow(location = "br", 
                                                     pad_x = unit(0.4, "in"), 
                                                     pad_y = unit(0.4, "in"),
                                                     style = north_arrow_fancy_orienteering) 

ecu_map_zoom <- ggmap(map) + xlab("Longitude") + 
          ylab("Latitude") + 
          ylim(-2.25, 1.4) +
          scalebar(x.min = -77, x.max = -75,
                   y.min = -2.1, y.max = -2.0,
                   dist = 100, 
                   dist_unit = "km", 
                   transform = T, 
                   model = "WGS84",
                   #st.bottom = F,
                   st.dist = 1,
                   height = 1, 
                   st.size = 3) +
          annotation_north_arrow(location = "br", 
                                 pad_x = unit(0.9, "in"), 
                                 pad_y = unit(0.4, "in"),
                                 style = north_arrow_fancy_orienteering)

ecu_map_piecharts <- ggmap(map) + xlab("Longitude") + 
          ylab("Latitude") + 
          ylim(-2.25, 1.6) +
          scalebar(x.min = -77, x.max = -75,
                   y.min = -2.1, y.max = -2.0,
                   dist = 100, 
                   dist_unit = "km", 
                   transform = T, 
                   model = "WGS84",
                   #st.bottom = F,
                   st.dist = 1,
                   height = 1, 
                   st.size = 3) +
          annotation_north_arrow(location = "br", 
                                 pad_x = unit(0.1, "in"), 
                                 pad_y = unit(3.2, "in"),
                                 style = north_arrow_fancy_orienteering)
ecuador_gmap_locations <- ecu_map + geom_point(data = ecu_epi, aes(x = lon, y = lat, fill = LocationCode), shape = 21, color = "black", size = 3) +   
          scale_fill_manual(values = loc_cols,
                            labels = locationLabels$LocationCode) +
  labs(fill = "Location")

save_plot("viz/ecuador_googlemap_samplinglocations.png", ecuador_gmap_locations)
ecuador_gmap_locations

Number of isolates sampled per year stratified by location - bar plot

ecu_epi <- ecu_epi %>% 
  mutate(Year = case_when(DateCollected < "2013-12-31" ~"2013",
                          DateCollected < "2014-12-31" ~"2014",
                          DateCollected < "2015-12-31" ~"2015",
                          TRUE ~"CHECK")) 

barplot_samples_perlocation <- ecu_epi %>% 
  group_by(LocationCode, Year) %>% 
  tally() %>% 
  ggplot(aes(x = Year, y = n, fill = LocationCode)) +
    geom_bar(stat = "identity") +
    scale_fill_manual(values = loc_cols,
                      labels = locationLabels$LocationCode) +
    background_grid(major = "xy", minor = "none") +
    labs(x = "Year", 
         y = "Number of samples",
         fill = "Location") +
    theme(legend.position = "none") +
    theme_cowplot() + 
    background_grid(major = "xy")

save_plot("viz/ecuador_barplot_sampling.png", barplot_samples_perlocation)
barplot_samples_perlocation 

Save sampling locations plot

Spatial network: google map

seg_data <- ecu_edges %>% filter(GS_score >= 0.5) 
seg_data <- seg_data %>% left_join(ecu_epi, by = c("id.x"="id"))
seg_data <- seg_data %>% left_join(ecu_epi, by = c("id.y"="id"))

seg_data <- seg_data %>% group_by(varcode.x, varcode.y, lon.x, lat.x, lon.y, lat.y) %>% tally()
ecu_map_zoom +
          geom_segment(data = seg_data,
                       aes(x = lon.x, y = lat.x, xend = lon.y, yend = lat.y, alpha = 0.1, size = n),
                       linejoin = "mitre") +
          geom_point(data = ecu_epi, 
                     aes(x = lon, y = lat, fill = varcode), 
                     shape = 21, color = "black", size = 3.5, 
                     position = position_jitter(h = 0.1, w = 0.1)) +
          scale_size_area() +
          scale_fill_manual(values = varcode_colors$varcode, 
                            labels = varcode_list) 

Real-time spatial network: google map

seg_data1 <- ecu_edges %>% filter(GS_score >= 0.5) 
seg_data1 <- seg_data1 %>% left_join(ecu_epi, by = c("id.x"="id"))
seg_data1 <- seg_data1 %>% left_join(ecu_epi, by = c("id.y"="id"))
seg_data1 <- seg_data1 %>% rename_at("DateCollected.x", ~"DateCollected")

googlemapSamplesRTNet <- ecu_map_zoom +
          geom_segment(data = seg_data1,
                       aes(x = lon.x, y = lat.x, xend = lon.y, yend = lat.y, alpha = 0.1, size = 0.5),
                       linejoin = "bevel") +
          geom_point(data = ecu_epi, 
                     aes(x = lon, y = lat, fill = varcode), 
                     shape = 21, color = "black", size = 3.5, 
                     position = position_jitter(h = 0.1, w = 0.1)) +
          scale_size_area() +
          scale_fill_manual(values = varcode_colors$varcode, 
                            labels = varcode_list) +
          scale_alpha(guide = "none") +
          scale_size(guide = "none") +
          transition_states(DateCollected, 
                          transition_length = 1, 
                          state_length = 5) +
          labs(title = "", 
               subtitle = 'Samples collected on {closest_state}') +
          shadow_mark(size = 3)

googlemapSamplesRTNet_anim <- animate(googlemapSamplesRTNet, width = 8, height = 8, res = 500, units = "in", duration = 15, fps = 2, detail = 5, render = gifski_renderer())
anim_save("viz/spatial_network_realtime_googlemap.gif", googlemapSamplesRTNet_anim)

googlemapSamplesRTNet_anim <- animate(googlemapSamplesRTNet, width = 8, height = 8, res = 250, units = "in", duration = 15, fps = 2, detail = 5, render = gifski_renderer())
anim_save("viz/spatial_network_realtime_googlemap_lowres.gif", googlemapSamplesRTNet_anim)

varcode pie charts:

Now we want to overlap pie charts with the proportion of isolates with each varcode identified in a given location in each year. This way we can include a map of the varcode locations that can be included in our figure showing the varcode persistence/maintenance over time.

varcode_piechartdata <- ecu_epi %>% group_by(LocationCode, lon, lat, Year, varcode) %>% tally()

ggplot(varcode_piechartdata, aes(x = "", y = n, fill = varcode)) +
  geom_bar(width = 1, stat = "identity", position = "fill") + 
  scale_fill_manual(values = varcode_colors$varcode, 
                    labels = varcode_list) +
  facet_wrap(~LocationCode) + 
  coord_polar(theta = "y", start = 0) +
  theme_void()

ggplot(varcode_piechartdata, aes(x = "", y = n, fill = varcode)) +
  geom_bar(width = 1, stat = "identity", position = "fill") + 
  scale_fill_manual(values = varcode_colors$varcode, 
                    labels = varcode_list) +
  facet_wrap(Year~LocationCode) + 
  coord_polar(theta = "y", start = 0) +
  theme_void()

Pie chart maps by year

First we need to create a dataframe with % varcode in each location.

df_location_varcode_totals <- ecu_epi %>% 
        tabyl(LocationCode, Year) %>% rename_at("2013", ~"total_2013") %>% rename_at("2014", ~"total_2014") %>% rename_at("2015", ~"total_2015") 

varcodes_by_loc <- ecu_epi %>% tabyl(LocationCode, varcode, Year)

varcode_prop_2013 <- varcodes_by_loc[[1]] %>% 
        adorn_totals("col") %>% 
        mutate(year = "2013") 

varcode_prop_2014 <- varcodes_by_loc[[2]] %>% 
        adorn_totals("col") %>% 
        mutate(year = "2014") 

varcode_prop_2015 <- varcodes_by_loc[[3]] %>% 
        adorn_totals("col") %>% 
        mutate(year = "2015") 
        


location_coords <- ecu_epi %>% group_by(LocationCode, lon, lat) %>% tally() %>% select(-n)

varcode_props <- rbind(varcode_prop_2013, varcode_prop_2014, varcode_prop_2015)
varcode_props <- varcode_props %>% left_join(location_coords, by = "LocationCode") %>% 
                                   select(LocationCode, lon, lat, year, Total, varcode1:varcode9) %>% 
                                   mutate(radius = (0.4 * sqrt(Total) / sqrt(max(Total)))) 

varcode spatial distribution: 2013

piecharts_2013 <- varcode_props %>% filter(year == "2013", Total > 0)

map_pies_2013 <- ecu_map_piecharts +
  geom_scatterpie(data = piecharts_2013, 
                  aes(x = lon, 
                      y = lat, 
                      r = radius,
                      group = LocationCode),
                  cols = c("varcode1", "varcode2", "varcode3", "varcode4", "varcode5", "varcode6", "varcode7", "varcode8", "varcode9")) +
  scale_fill_manual(breaks = varcode_list,
                    values = varcode_colors$varcode, 
                    labels = varcode_list) +
  geom_scatterpie_legend(piecharts_2013$radius, 
                         n = 2, 
                         labeller = function(x) x = unique(piecharts_2013$Total),
                         x = -75.6, 
                         y = -1.5) 

save_plot("viz/ecuador_googlemap_piecharts2013.png", map_pies_2013, base_width = 8, base_height = 6)
map_pies_2013

varcode spatial distribution: 2014

piecharts_2014 <- varcode_props %>% filter(year == "2014", Total > 0)

map_pies_2014 <- ecu_map_piecharts +
  geom_scatterpie(data = piecharts_2014, 
                  aes(x = lon, 
                      y = lat, 
                      r = radius,
                      group = LocationCode),
                  cols = c("varcode1", "varcode2", "varcode3", "varcode4", "varcode5", "varcode6", "varcode7", "varcode8", "varcode9")) +
  scale_fill_manual(breaks = varcode_list,
                    values = varcode_colors$varcode, 
                    labels = varcode_list) +
  geom_scatterpie_legend(piecharts_2014$radius, 
                         n = 3, 
                         labeller = function(x) x = unique(piecharts_2014$Total),
                         x = -75.4, 
                         y = -1.6) 

save_plot("viz/ecuador_googlemap_piecharts2014.png", map_pies_2014, base_width = 8, base_height = 6)
map_pies_2014

varcode spatial distribution: 2014

piecharts_2015 <- varcode_props %>% filter(year == "2015", Total > 0)

map_pies_2015 <- ecu_map_piecharts +
  geom_scatterpie(data = piecharts_2015, 
                  aes(x = lon, 
                      y = lat, 
                      r = radius,
                      group = LocationCode),
                  cols = c("varcode1", "varcode2", "varcode3", "varcode4", "varcode5", "varcode6", "varcode7", "varcode8", "varcode9")) +
  scale_fill_manual(breaks = varcode_list,
                    values = varcode_colors$varcode, 
                    labels = varcode_list) +
  geom_scatterpie_legend(piecharts_2015$radius, 
                         n = 3, 
                         labeller = function(x) x = unique(piecharts_2015$Total),
                         x = -75.4, 
                         y = -1.6) 

save_plot("viz/ecuador_googlemap_piecharts2015.png", map_pies_2015, base_width = 8, base_height = 6)
map_pies_2015

Leaflet just to visualize

Spatial varcode network

data_piechartnetwork <- ecu_epi %>%
        tabyl(LocationCode, varcode) %>% 
        adorn_totals("col") %>% 
        mutate(radius = (0.3 * sqrt(Total) / sqrt(max(Total)))) %>% left_join(location_coords, by = "LocationCode")

map_pies_network <- ggmap(map) + xlab("Longitude") + 
          ylab("Latitude") + 
          ylim(-2.2, 1.6) +
          scalebar(x.min = -77, x.max = -75,
                   y.min = -2.1, y.max = -2.0,
                   dist = 100, 
                   dist_unit = "km", 
                   transform = T, 
                   model = "WGS84",
                   #st.bottom = F,
                   st.dist = 1,
                   height = 1, 
                   st.size = 3) +
          annotation_north_arrow(location = "br", 
                                 pad_x = unit(0.1, "in"), 
                                 pad_y = unit(3.2, "in"),
                                 style = north_arrow_fancy_orienteering) +
          geom_segment(data = seg_data,
                       aes(x = lon.x, y = lat.x, xend = lon.y, yend = lat.y, alpha = 0.1, size = n),
                       linejoin = "mitre") +
  geom_scatterpie(data = data_piechartnetwork, 
                  aes(x = lon, 
                      y = lat, 
                      r = radius,
                      group = LocationCode),
                  cols = c("varcode1", "varcode2", "varcode3", "varcode4", "varcode5", "varcode6", "varcode7", "varcode8", "varcode9")) +
  scale_fill_manual(breaks = varcode_list,
                    values = varcode_colors$varcode, 
                    labels = varcode_list) +
  scale_alpha(guide = "none") +
  scale_size(guide = "none") +
  geom_scatterpie_legend(data_piechartnetwork$radius, 
                         n = 5, 
                         labeller = function(x) x = sort(unique(data_piechartnetwork$Total)),
                         x = -75.4, 
                         y = -1.6) 
Scale for 'y' is already present. Adding another scale for 'y', which will replace the existing scale.
save_plot("viz/ecuador_googlemap_spatialnetwork.png", map_pies_network, base_width = 8, base_height = 6)
map_pies_network

South America

MOI in South America

data_MOI <- data.frame(colSums(matrix_all))
colnames(data_MOI) <- c("repertoire_size")
data_MOI <- data_MOI %>% rownames_to_column("SampleID")

data_MOI$Location <- ifelse(grepl("^G", data_MOI$SampleID, ignore.case = T), "French Guiana",
                                  ifelse(grepl("^P", data_MOI$SampleID, ignore.case = T), "Peru",
                                         ifelse(grepl("^V", data_MOI$SampleID, ignore.case = T), "Venezuela",
                                                ifelse(grepl("^Col", data_MOI$SampleID, ignore.case = T), "Colombia",
                                                      ifelse(grepl("^ECPf", data_MOI$SampleID, ignore.case = T), "Ecuador", "CHECK")))))
data_MOI$Location <- as.factor(data_MOI$Location)
levels(data_MOI$Location)

What are the summary statistics for MOI?

kable(data_MOI %>% group_by(Location) %>% summarize(min = min(repertoire_size), med = median(repertoire_size), mean = mean(repertoire_size), max = max(repertoire_size))) %>% kable_styling()
`summarise()` ungrouping output (override with `.groups` argument)
Location min med mean max
Colombia 19 40.0 38.42857 43
Ecuador 11 37.0 36.58621 43
French Guiana 13 48.0 50.50000 92
Peru 19 36.0 33.42857 42
Venezuela 28 36.5 35.20000 43

Set the color scale for each country

country_list <- data_MOI %>% select(SampleID, Location)
country_list$SampleID <- as.factor(country_list$SampleID)
country_list$Location <- as.factor(country_list$Location)
country_list <- country_list %>% column_to_rownames("SampleID")

country_colors <- list(Location = c("Colombia" = "#fdb462", "Ecuador" = "#fb8072", "French Guiana" = "#a6d854", "Peru" = "#66c2a5", "Venezuela" = "#bebada"))

What are the MOI patterns in South American P. falciparum isolates?

plot_MOI_SAm <- ggplot(data = data_MOI, aes(x = factor(SampleID), fill = Location)) + 
  geom_bar(aes(y = repertoire_size), stat = "identity") +
  scale_fill_manual(values = country_colors$Location,
                       labels = country_list) +
  scale_y_continuous(breaks = seq(0, 100, by = 30)) + 
  labs(x = "Isolate",
       y = "Repertoire size",
       fill = "") +
  theme_cowplot() +
  theme(axis.text.x = element_blank(),
        axis.ticks.x = element_blank()) + #element_text(angle = 90, vjust = 0.5)) +
  background_grid(major = "y", minor = "none")

save_plot("viz/SAm_MOI.png", plot_MOI_SAm)
plot_MOI_SAm

Number of shared types by country: South America

Create a presence/absence matrix just of each country as a population (not isolate by isolate)

country_matrix <- matrix_all %>% as.data.frame() %>% rownames_to_column("DBLa_type") %>% 
                                 mutate(Colombia = rowSums(.[grepl("^Col", colnames(.))], na.rm = T),
                                        Ecuador = rowSums(.[grepl("^ECPf", colnames(.))], na.rm = T),
                                        `French Guiana` = rowSums(.[grepl("^G", colnames(.))], na.rm = T),
                                        Peru = rowSums(.[grepl("^P", colnames(.))], na.rm = T),
                                        Venezuela = rowSums(.[grepl("^V", colnames(.))], na.rm = T)) %>% 
                                 select(DBLa_type, Colombia:Venezuela)

country_matrix <- country_matrix %>% mutate(Colombia = ifelse(Colombia > 0, 1, 0),
                                            Ecuador = ifelse(Ecuador > 0, 1, 0),
                                            `French Guiana` = ifelse(`French Guiana` > 0, 1, 0),
                                            Peru = ifelse(Peru > 0, 1, 0),
                                            Venezuela = ifelse(Venezuela > 0, 1, 0)) %>% 
                                     column_to_rownames("DBLa_type")
write.csv(country_matrix, "data/country_binary.csv")
The number of shared types identified in the countries was as follows:
shared n
1 327
2 124
3 59
4 28
5 5

.

Clustered Heatmap South America

We can also plot this as a heatmap, which clusters the countries by the number of types they share. Therefore, countries that share more types will be clustered together.

Country <- c("Colombia (N=112)", "Ecuador (N=195)", "French Guiana (N=249)", "Peru (N=157)", "Venezuela (N=176)")
location <- c("Colombia (N=112)", "Ecuador (N=195)", "French Guiana (N=249)", "Peru (N=157)", "Venezuela (N=176)")
anno_cols <- data.frame(location, Country)
anno_cols <- anno_cols %>% column_to_rownames("location")
colors_anno <- list(Country = c(`Colombia (N=112)` = "#fdb462", `Ecuador (N=195)` = "#66c2a5", `French Guiana (N=249)` = "#a6d854", `Peru (N=157)` = "#fb8072", `Venezuela (N=176)` = "#bebada"))

country_heatmap <- pheatmap(t(country_matrix), col = c("white", "black"), annotation_row = anno_cols, annotation_colors = colors_anno, fontsize_row = 5, fontsize_col = 5, show_colnames = F, show_rownames = F, legend = F, treeheight_col = 0)

save_plot("viz/SAm_country_heatmap.png", country_heatmap, base_width = 8, base_height = 4)
country_heatmap

Genetic Similarity and Network Analysis: South America

For the directional PTS among South American isolates, we consider both the “forward” and “reverse” direction since there is not real temporal aspect to this dataset. The sampling locations and sampling times differ greatly, so we are only interested in identifying cluster of genetically-related parasites in space and/or time (i.e. not recent transmission events or “real-time” recombinations).

genSim_all <- geneticSimilarity(t(matrix_all))
GStable_all <- GSmatrixToTable(genSim_all) 

Here we do not need to select only the “backwards in time” direction, because the times between sampling collections vary greatly. We are only interested in identifying genetically-related parasites in space and time (i.e. not epidemiological time but perhaps evolutionary time). Because we don’t know if the order matters (i.e. different countries) we can use both directions.

Create an epi dataset for South America.

all_epi <- data_MOI %>% mutate(id = 1:nrow(.))
GSall_edges <- GStable_all %>% left_join(all_epi, by = c("SampleID1" = "SampleID")) %>% rename(id.x = id)
GSall_edges <- GSall_edges %>% left_join(all_epi, by = c("SampleID2" = "SampleID")) %>% rename(id.y = id)
GSall_edges <- GSall_edges %>% select(id.x, id.y, GS_score)

SAm_tidy <- tbl_graph(nodes = all_epi, edges = GSall_edges, directed = T)

Defining varcodes: South America

SAm_varcodes_network <- SAm_tidy %>% activate(edges) %>% filter(GS_score >= 0.9) %>% 
  ggraph(layout = "fr") + 
  geom_edge_link(color = "darkgrey", alpha = 0.5) + 
  geom_node_point(aes(fill = Location), shape = 21, color = "black", size = 3) +
  scale_fill_manual(values = country_colors$Location,
                       labels = country_list) +
 # geom_node_text(aes(label = SampleID), repel = TRUE) +
  labs(edge_width = "SampleID",
       fill = "") +
  theme_graph()

save_plot("viz/SAm_varcode_network.png", SAm_varcodes_network, base_width = 8, base_height = 6)
SAm_varcodes_network

Genetic Similarity Networks: South America

SAm_recombinants_network <- SAm_tidy %>% #filter(SampleID != "ECPf004", SampleID != "ECPf011") %>% 
  activate(edges) %>% filter(GS_score >= 0.5) %>% 
  ggraph(layout = "fr") + 
  geom_edge_link(color = "darkgrey", alpha = 0.5) + 
  geom_node_point(aes(fill = Location), shape = 21, color = "black", size = 3) +
  scale_fill_manual(values = country_colors$Location,
                       labels = country_list) +
 # geom_node_text(aes(label = SampleID), repel = TRUE) +
  labs(edge_width = "SampleID",
       fill = "") +
  theme_graph() 

save_plot("viz/SAm_recombinants_network.png", SAm_recombinants_network, base_width = 8, base_height = 6)
SAm_recombinants_network

Genetic similarity: varcodes and South America

We can also calculate the number of shared types or genetic similarity of the varcodes with South American isolates to corroborate the network visualizations (and add a quantitative measure). We need to recreate the varcode matrix with all 543 types identified in South America.

varcode_vec <- ecu_epi %>% select(SampleID, varcode)
varcode_vec$SampleID <- as.factor(varcode_vec$SampleID)
varcode_vec$varcode <- as.factor(varcode_vec$varcode)

vc1_matrixSAM <- matrix_all[, colnames(matrix_all) %in% subset(varcode_vec, varcode == "varcode1")$SampleID]
vc2_matrixSAM <- matrix_all[, colnames(matrix_all) %in% subset(varcode_vec, varcode == "varcode2")$SampleID]
vc3_matrixSAM <- matrix_all[, colnames(matrix_all) %in% subset(varcode_vec, varcode == "varcode3")$SampleID]
vc4_matrixSAM <- matrix_all[, colnames(matrix_all) %in% subset(varcode_vec, varcode == "varcode4")$SampleID]
vc5_matrixSAM <- matrix_all[, colnames(matrix_all) %in% subset(varcode_vec, varcode == "varcode5")$SampleID]
vc6_matrixSAM <- matrix_all[, colnames(matrix_all) %in% subset(varcode_vec, varcode == "varcode6")$SampleID]
vc7_matrixSAM <- matrix_all[, colnames(matrix_all) %in% subset(varcode_vec, varcode == "varcode7")$SampleID]
vc8_matrixSAM <- matrix_all[, colnames(matrix_all) %in% subset(varcode_vec, varcode == "varcode8")$SampleID]
vc9_matrixSAM <- matrix_all[, colnames(matrix_all) %in% subset(varcode_vec, varcode == "varcode9")$SampleID]

vc1_matrixSAM_sum <- rowSums(vc1_matrixSAM) %>% as.data.frame()
vc1_matrixSAM_sum <- vc1_matrixSAM_sum %>% mutate(varcode1 = ifelse(. > 0, 1, 0)) %>% select(varcode1)
rownames(vc1_matrixSAM_sum) <- rownames(vc1_matrixSAM)

vc2_matrixSAM_sum <- rowSums(vc2_matrixSAM) %>% as.data.frame()
vc2_matrixSAM_sum <- vc2_matrixSAM_sum %>% mutate(varcode2 = ifelse(. > 0, 1, 0)) %>% select(varcode2)
rownames(vc2_matrixSAM_sum) <- rownames(vc2_matrixSAM)

vc3_matrixSAM_sum <- rowSums(vc3_matrixSAM) %>% as.data.frame()
vc3_matrixSAM_sum <- vc3_matrixSAM_sum %>% mutate(varcode3 = ifelse(. > 0, 1, 0)) %>% select(varcode3)
rownames(vc3_matrixSAM_sum) <- rownames(vc3_matrixSAM)

vc4_matrixSAM_sum <- as.data.frame(vc4_matrixSAM) %>% rename_at("vc4_matrixSAM", ~"varcode4")
vc5_matrixSAM_sum <- as.data.frame(vc5_matrixSAM) %>% rename_at("vc5_matrixSAM", ~"varcode5")

vc6_matrixSAM_sum <- rowSums(vc6_matrixSAM) %>% as.data.frame()
vc6_matrixSAM_sum <- vc6_matrixSAM_sum %>% mutate(varcode6 = ifelse(. > 0, 1, 0)) %>% select(varcode6)
rownames(vc6_matrixSAM_sum) <- rownames(vc6_matrixSAM)

vc7_matrixSAM_sum <- rowSums(vc7_matrixSAM) %>% as.data.frame()
vc7_matrixSAM_sum <- vc7_matrixSAM_sum %>% mutate(varcode7 = ifelse(. > 0, 1, 0)) %>% select(varcode7)
rownames(vc7_matrixSAM_sum) <- rownames(vc7_matrixSAM)

vc8_matrixSAM_sum <- rowSums(vc8_matrixSAM) %>% as.data.frame()
vc8_matrixSAM_sum <- vc8_matrixSAM_sum %>% mutate(varcode8 = ifelse(. > 0, 1, 0)) %>% select(varcode8)
rownames(vc8_matrixSAM_sum) <- rownames(vc8_matrixSAM)

vc9_matrixSAM_sum <- as.data.frame(vc9_matrixSAM) %>% rename_at("vc9_matrixSAM", ~"varcode9")

varcode_matrixSAM <- bind_cols(vc1_matrixSAM_sum, vc2_matrixSAM_sum, vc3_matrixSAM_sum, vc4_matrixSAM_sum, vc5_matrixSAM_sum, vc6_matrixSAM_sum, vc7_matrixSAM_sum, vc8_matrixSAM_sum, vc9_matrixSAM_sum)
rownames(varcode_matrixSAM) <- rownames(vc1_matrixSAM_sum)
The total number of types in each varcode is now:
x
varcode1 47
varcode2 41
varcode3 40
varcode4 42
varcode5 34
varcode6 45
varcode7 43
varcode8 42
varcode9 35

(which is identical to before with only N=195 types).

Create the varcode and country matrix

country_matrix_temp <- country_matrix %>% as.data.frame() %>% 
                                          rownames_to_column("DBLa_type")
varcode_matrixSAM_final <- varcode_matrixSAM %>% rownames_to_column("DBLa_type") %>% 
                                                 left_join(country_matrix_temp, by = "DBLa_type")
varcode_matrixSAM_final <- varcode_matrixSAM_final %>% column_to_rownames("DBLa_type") 

varcode_matrixSAM_final <- varcode_matrixSAM_final %>%  rename_at("varcode1", ~"varcode1 (N=47)") %>% 
                                                        rename_at("varcode2", ~"varcode2 (N=41)" ) %>% 
                                                        rename_at("varcode3", ~"varcode3 (N=40)") %>% 
                                                        rename_at("varcode4", ~"varcode4 (N=42)") %>% 
                                                        rename_at("varcode5", ~"varcode5 (N=34)") %>% 
                                                        rename_at("varcode6", ~"varcode6 (N=45)") %>% 
                                                        rename_at("varcode7", ~"varcode7 (N=43)") %>% 
                                                        rename_at("varcode8", ~"varcode8 (N=42)") %>% 
                                                        rename_at("varcode9", ~"varcode9 (N=35)") %>% 
                                                        rename_at("Colombia", ~"Colombia (N=112)") %>% 
                                                        rename_at("Ecuador", ~"Ecuador (N=195)") %>% 
                                                        rename_at("French Guiana", ~"French Guiana (N=249)") %>% 
                                                        rename_at("Peru", ~"Peru (N=157)") %>% 
                                                        rename_at("Venezuela", ~"Venezuela (N=176)")

varcode_matrixSAM_final <- varcode_matrixSAM_final %>% as.matrix()

As we did before, for the directional PTS among the varcodes and South American isolates, we consider both the “forward” and “reverse” direction since there is not real temporal aspect to this dataset. The sampling locations and sampling times differ greatly, so we are only interested in identifying cluster of genetically-related parasites in space and/or time (i.e. not recent transmission events or “real-time” recombinations).

genSim_varcodeSAM <- geneticSimilarity(t(varcode_matrixSAM_final))
GStable_varcodeSAM <- GSmatrixToTable(genSim_varcodeSAM) 

countryNs_colors <- list(Location = c("Colombia\n(N=112)" = "#fdb462", "Ecuador\n(N=195)" = "#fb8072", "French Guiana\n(N=249)" = "#a6d854", "Peru\n(N=157)" = "#66c2a5", "Venezuela\n(N=176)" = "#bebada"))

varcode_country_tileplot <- GStable_varcodeSAM %>% filter(SampleID1 %like% "varcode", !SampleID2 %like% "varcode") %>% 
    mutate(SampleID2 = case_when(SampleID2 == "Colombia (N=112)" ~"Colombia\n(N=112)",
                                 SampleID2 == "Ecuador (N=195)" ~"Ecuador\n(N=195)",
                                 SampleID2 == "French Guiana (N=249)" ~ "French Guiana\n(N=249)",
                                 SampleID2 == "Peru (N=157)" ~ "Peru\n(N=157)",
                                 SampleID2 == "Venezuela (N=176)" ~ "Venezuela\n(N=176)")) %>% 
    ggplot(aes(x = SampleID2, y = SampleID1, fill = SampleID2)) +
        geom_tile(aes(alpha = GS_score)) +
        scale_fill_manual(values = countryNs_colors$Location,
                          labels = c("Colombia\n(N=112)", "Ecuador\n(N=195)", "French Guiana\n(N=249)", "Peru\n(N=157)", "Venezuela\n(N=176)"),
                      guide = "none") +
        geom_text(aes(label = round(GS_score, 2))) +
        theme(#axis.text.x = element_text(angle = 90),
              axis.title.x = element_blank(),
              axis.title.y = element_blank()) +
        theme_cowplot() +
        labs(x = "",
             y = "",
             fill = "",
             alpha = expression(paste("P"["TS"], " score")))

save_plot("viz/varcode_country_tileplot.png", varcode_country_tileplot, base_width = 8, base_height = 4)
varcode_country_tileplot

Outbreak varcode1: evolutionary history of types

outbreak_recomb_evo <- varcode_matrixSAM %>%
                            rownames_to_column("DBLa_type") %>%  
                            select(DBLa_type, varcode1, varcode3, varcode4, varcode6, varcode7) %>% 
                            filter(varcode1 > 0) 

outbreak_recomb_evo_mat <- outbreak_recomb_evo %>% column_to_rownames("DBLa_type") %>% as.matrix()

recomb_names <- data.frame(varcode = c("varcode1", "varcode3", "varcode4", "varcode6", "varcode7"),
                           varcode_name = c("varcode1", "varcode3", "varcode4", "varcode6", "varcode7")) %>%
             column_to_rownames("varcode_name")

colors_recomb <- list(varcode = c("varcode1" = "#fb9a99", "varcode3" = "#48B24F", "varcode4" = "#30d5c8", "varcode6" = "#3090d5", "varcode7" = "#CAD93F"))

#heatmap_outbreak_recomb <- 
pheatmap(t(outbreak_recomb_evo_mat), 
         col = c("white", "black"), 
         annotation_row = recomb_names, 
         annotation_colors = colors_recomb,
         fontsize_row = 5, 
         fontsize_col = 5, 
         show_colnames = F, 
         show_rownames = F, 
         #filename = "viz/heatmap_outbreaktypes_recombinants.png",
         legend = F, 
         treeheight_col = 0,
         width = 8, 
         height = 4)


pheatmap(t(outbreak_recomb_evo_mat), 
         col = c("white", "black"), 
         annotation_row = recomb_names, 
         annotation_colors = colors_recomb,
         cluster_rows = F,
         fontsize_row = 5, 
         fontsize_col = 5, 
         show_colnames = F, 
         show_rownames = F, 
         #filename = "viz/heatmap_outbreaktypes_recombinants_nocluster.png",
         legend = F, 
         treeheight_col = 0,
         width = 8, 
         height = 4)


outbreak_recomb_evo %>% 
  melt() %>% 
  ggplot(aes(x = reorder(DBLa_type, value), y = variable, fill = factor(value))) + 
    geom_tile(color = "grey") +
    scale_fill_manual(values = c("0" = "white", "1" = "black"),
                      labels = c("absence", "presence")) +
    theme(axis.text.x = element_blank()) +
    #theme_cowplot() +
    labs(x = "varcode1 DBLα types (N=47)",
         y = "",
         fill = "")
Using DBLa_type as id variables

outbreak_evohistory <- varcode_matrixSAM_final %>% as.data.frame() %>% 
                            rownames_to_column("DBLa_type") %>%  
                            select(DBLa_type, `varcode1 (N=47)`, `Colombia (N=112)`, `Peru (N=157)`, `Venezuela (N=176)`, `French Guiana (N=249)`) %>% 
                            filter(`varcode1 (N=47)` > 0) %>% 
                            mutate(sum = `varcode1 (N=47)` + `Colombia (N=112)` + `Peru (N=157)` + `Venezuela (N=176)` + `French Guiana (N=249)`) %>% 
                            rename_at("varcode1 (N=47)", ~"varcode1") %>% 
                            rename_at("Colombia (N=112)", ~"Colombia") %>% 
                            rename_at("Peru (N=157)", ~"Peru") %>% 
                            rename_at("French Guiana (N=249)", ~"French Guiana") %>% 
                            rename_at("Venezuela (N=176)", ~"Venezuela")

outbreak_evohistory %>% group_by(sum) %>% tally()

#varcode_matrixSAM_final %>% as.data.frame() %>% rownames_to_column("DBLa_type") %>% filter(DBLa_type %in% subset(outbreak_evohistory, sum == 1)$DBLa_type) %>% View()

outbreak_evohistory_mat <- outbreak_evohistory %>% select(-sum) %>% column_to_rownames("DBLa_type") %>% as.matrix()

evo_names <- data.frame(`.` = c("varcode1", "Colombia", "French Guiana", "Peru", "Venezuela"),
                        location = c("varcode1","Colombia", "French Guiana", "Peru", "Venezuela")) %>% 
             column_to_rownames("location")

colors_evo <- list(`.` = c(`varcode1` = "#fb8072", `Colombia` = "#fdb462", `French Guiana` = "#a6d854", `Peru` = "#66c2a5", `Venezuela` = "#bebada"))

#heatmap_outbreak_SAm <- 
pheatmap(t(outbreak_evohistory_mat), 
         col = c("white", "black"), 
         annotation_row = evo_names, 
         annotation_colors = colors_evo,
         fontsize_row = 5, 
         fontsize_col = 5, 
         show_colnames = F, 
         show_rownames = F, 
         #filename = "viz/heatmap_outbreaktypes.png",
         legend = F, 
         treeheight_col = 0,
         width = 8, 
         height = 4)


pheatmap(t(outbreak_evohistory_mat), 
         col = c("white", "black"), 
         annotation_row = evo_names, 
         annotation_colors = colors_evo,
         cluster_rows = F, 
         cluster_cols = F, 
         fontsize_row = 5, 
         fontsize_col = 5, 
         show_colnames = F, 
         show_rownames = F, 
         #filename = "viz/heatmap_outbreaktypes_nocluster.png",
         legend = F, 
         treeheight_col = 0,
         width = 8, 
         height = 4)


outbreak_evohistory %>% select(-sum) %>% 
  melt() %>% 
  ggplot(aes(x = reorder(DBLa_type, value), y = variable, fill = factor(value))) + 
    geom_tile(color = "grey") +
    scale_fill_manual(values = c("0" = "white", "1" = "black"),
                      labels = c("absence", "presence")) +
    theme(axis.text.x = element_blank()) +
    #theme_cowplot() +
    labs(x = "varcode1 DBLα types (N=47)",
         y = "",
         fill = "")
Using DBLa_type as id variables

Heatmap of varcode1

vc1_47types <- vc1_matrixSAM %>% as.data.frame() %>% 
  rownames_to_column("DBLa_type") %>% 
  filter(DBLa_type %in% outbreak_recomb_evo$DBLa_type)

vc1_47types <- vc1_47types %>% left_join(select(outbreak_metadata, DBLa_type, freq), by = "DBLa_type") %>% arrange(desc(freq))

vc1_matrix_47types <- vc1_47types %>% select(-freq) %>% column_to_rownames("DBLa_type") %>% as.matrix() 

varcode1_list <- varcode_list %>% rownames_to_column("SampleID") %>% left_join(select(ecu_epi, SampleID, Case), by = "SampleID") %>% filter(SampleID %in% names(vc1_47types)) %>% column_to_rownames("Case") %>% select(-SampleID)

vc1_matrix_47types <- t(vc1_matrix_47types)
rownames(vc1_matrix_47types) <- rownames(varcode1_list)

vc1_col <- list(varcode = c("varcode1" = "#fb9a99"))

#heatmap_outbreakvc1 <- 
pheatmap(vc1_matrix_47types, col = c("white", "black"),
         annotation_row = varcode1_list, 
         annotation_colors = vc1_col, 
         fontsize_row = 5, fontsize_col = 5, 
         cluster_rows = F, 
         cluster_cols = F, 
         legend = F, 
         treeheight_col = 0, 
         show_colnames = F,
         show_rownames = T, 
         #filename = "viz/heatmap_varcode1_nocluster.png",
         width = 8, 
         height = 4)


#broken
vc1_47types %>% select(-freq) %>% 
  melt(id = "DBLa_type") %>% 
  rename_at("variable", ~"isolate") %>% 
  left_join(select(ecu_epi, SampleID, Case), by = c("isolate" = "SampleID")) %>% 
  mutate(Case2 = paste("EC",sprintf("%02s", substr(Case,3,5)))) %>% 
  ggplot(aes(x = reorder(DBLa_type, desc(value)), y = Case2, fill = factor(value))) + 
    geom_tile(color = "grey") +
    scale_fill_manual(values = c("0" = "white", "1" = "black"),
                      labels = c("absence", "presence")) +
    theme(axis.text.x = element_blank()) +
    #theme_cowplot() +
    labs(x = "varcode1 DBLα types (N=47)",
         y = "Case",
         fill = "")

Conservation of outbreak types

# frequency of types in outbreak clone
outbreak_metadata %>% summarise(min = min(freq), mean = mean(freq), median = median(freq), max = max(freq), sum = sum(freq)) 

#sum of observations of types in outbreak clone
outbreak_metadata %>% filter(freq > 1) %>% summarise(sum = sum(freq)) 

# frequency of types in outbreak clone excluding singletons 
outbreak_metadata %>% filter(freq > 1) %>% summarise(min = min(freq), mean = mean(freq), median = median(freq), max = max(freq), sum = sum(freq)) 

# frequency of types in outbreak clone excluding low freq types 
outbreak_metadata %>% filter(freq > 4) %>% summarise(min = min(freq), mean = mean(freq), median = median(freq), max = max(freq), sum = sum(freq))

#frequency of outbreak types in recombinant varcodes
typefreq_outbreak_recomb <- outbreak_metadata %>% left_join(vc3_matrixSAM %>% 
                                                              rowSums() %>% 
                                                              as.data.frame() %>% 
                                                              rename_at(".", ~ "freq_vc3") %>% 
                                                              rownames_to_column("DBLa_type"), 
                                                            by = "DBLa_type")

typefreq_outbreak_recomb <- typefreq_outbreak_recomb %>% left_join(vc4_matrixSAM %>% 
                                                                     as.data.frame() %>% 
                                                                     rename_at(".", ~ "freq_vc4") %>% 
                                                                     rownames_to_column("DBLa_type"), 
                                                                   by = "DBLa_type")

typefreq_outbreak_recomb <- typefreq_outbreak_recomb %>% left_join(vc6_matrixSAM %>% 
                                                                     rowSums() %>% 
                                                                     as.data.frame() %>% 
                                                                     rename_at(".", ~ "freq_vc6") %>% 
                                                                     rownames_to_column("DBLa_type"), 
                                                                   by = "DBLa_type")

typefreq_outbreak_recomb <- typefreq_outbreak_recomb %>% left_join(vc7_matrixSAM %>% 
                                                                     rowSums() %>% 
                                                                     as.data.frame() %>% 
                                                                     rename_at(".", ~ "freq_vc7") %>% 
                                                                     rownames_to_column("DBLa_type"), 
                                                                   by = "DBLa_type")

typefreq_outbreak_recomb <- typefreq_outbreak_recomb %>% mutate(freq_recomb = freq_vc3 + freq_vc4 + freq_vc6 + freq_vc7)

#frequency of outbreak types in recombinant varcodes (3,4,6,7)
typefreq_outbreak_recomb %>% summarise(min = min(freq_recomb), mean = mean(freq_recomb), median = median(freq_recomb), max = max(freq_recomb), sum = sum(freq_recomb)) 

#how many of the 47 DBLa types were identified in the recombinants?
typefreq_outbreak_recomb %>% filter(freq_recomb > 0) %>% nrow()

#how many of the 47 DBLa types were identified in each recombinant? (and proportion)
typefreq_outbreak_recomb %>% filter(freq_vc3 > 0) %>% nrow() 
27/47
typefreq_outbreak_recomb %>% filter(freq_vc4 > 0) %>% nrow() 
26/47
typefreq_outbreak_recomb %>% filter(freq_vc6 > 0) %>% nrow() 
17/47
typefreq_outbreak_recomb %>% filter(freq_vc7 > 0) %>% nrow() 
26/47

Conservation of Ecuadorian types

Neighbor-Joining Tree Analysis

South America

Now I will use the ape and ggtree package to create an unrooted neighbor-joining tree. We will use 1-GS to represent genetic distance (i.e. PTD as in Rougeron et al 2017). Therefore, a value of 0 would indicate identical repertoires, i.e. 0 genetic distance from each other. For future reference I used this tutorial.

Epidemiology Analysis

Now we want to characterize the epidemiology surrounding the outbreak cases and those post-outbreak. Are there any particular risk factors (location, age, sex)? Undoubtedly, location will be a risk factor, but let’s quantify this. To explore the demographics of the individuals harboring cases we focus on two broad stratification groups: 1. Outbreak cases (N=30) 2. Non-outbreak cases (N=28).

We also focus on the following stratification groups based on our varcode genetic data: 1. Cases caused by outbreak clone (varcode1 in 2013) 2. Cases caused by varcode1 after the outbreak (2014 or 2015) 3. Cases caused by recombinants of varcode1 4. Cases caused by different varcodes.

What are the demographic characteristics of the 50 study participants with epi data?

Note we don’t have age and sex data for 8 participants.

ecu_epi %>% filter(!is.na(Age) & !is.na(Sex)) %>% summarize(min = min(Age), med = median(Age), avg = mean(Age), max = max(Age)) 
ecu_epi %>% filter(!is.na(Age) & !is.na(Sex)) %>% group_by(Sex) %>% tally()  

What are the demographic characteristics of individuals with P. falciparum cases during the outbreak?

ecu_epi %>% filter(Year== "2013") %>% group_by(Sex) %>% tally() 

ecu_epi %>% filter(Year == "2013", !is.na(Age)) %>% summarize(min = min(Age), med = median(Age), avg = mean(Age), max = max(Age)) 
ecu_epi %>% filter(Year == "2013", !is.na(Age)) %>% group_by(Sex) %>% summarize(min = min(Age), med = median(Age), avg = mean(Age), max = max(Age))  
The summary statistics for the ages of individuals with cases during the outbreak is:
min med avg max
9 23 26.36667 57
The summary statistics for the ages of individuals with cases during the outbreak, stratified by sex is:
Sex min med avg max
F 13 16.5 23.25000 57
M 9 31.5 28.44444 45

Was there a significant difference in the distribution of ages of males or females with cases during the outbreak?

wilcox.test(Age ~ Sex, data = ecu_epi %>% filter(Outbreak == "Outbreak2013", !is.na(Age)), exact = F, paired = F)

    Wilcoxon rank sum test with continuity correction

data:  Age by Sex
W = 67, p-value = 0.3789
alternative hypothesis: true location shift is not equal to 0

There was no significant difference in the ages of males or females who had P. falciparum cases during the outbreak (p = 0.38).

What are the demographic characteristics of individuals with P. falciparum cases during and after the outbreak?

ecu_epi %>% group_by(OutbreakBinary) %>% tally() 
ecu_epi %>% group_by(OutbreakBinary, Sex) %>% tally()  
ecu_epi %>% group_by(OutbreakBinary, is.na(Age)) %>% tally() 
ecu_epi %>% filter(!is.na(Sex) & !is.na(Age)) %>% group_by(OutbreakBinary) %>% tally() 
ecu_epi %>% filter(!is.na(Age)) %>% group_by(OutbreakBinary) %>% summarize(min = min(Age), med = median(Age), avg = mean(Age), max = max(Age)) 
ecu_epi %>% filter(!is.na(Age)) %>% group_by(OutbreakBinary, Sex) %>% summarize(min = min(Age), med = median(Age), avg = mean(Age), max = max(Age)) 
We have data for age and sex for the following participants:
OutbreakBinary n
NotOutbreak2013 21
Outbreak2013 27
The summary statistics for the ages of individuals with cases during and after the outbreak is:
OutbreakBinary min med avg max
NotOutbreak2013 15 25 29.38095 58
Outbreak2013 9 25 27.03704 57
The summary statistics for the ages of individuals with cases during and after the outbreak, stratified by sex is:
OutbreakBinary Sex min med avg max
NotOutbreak2013 F 15 30.0 32.75000 58
NotOutbreak2013 M 17 25.0 27.30769 52
Outbreak2013 F 13 17.5 24.80000 57
Outbreak2013 M 9 33.0 28.35294 45

Was there a significant difference in the ages of individuals with P. falciparum cases during and after the outbreak?

wilcox.test(Age ~ OutbreakBinary, data = ecu_epi %>% filter(!is.na(Age)), exact = F, paired = F)

    Wilcoxon rank sum test with continuity correction

data:  Age by OutbreakBinary
W = 325.5, p-value = 0.3878
alternative hypothesis: true location shift is not equal to 0

There was no significant difference in the ages of individuals who had P. falciparum cases during or after the outbreak (p = 0.39).

Was there a significant difference in the ages of males or females with P. falciparum cases after the outbreak?

wilcox.test(Age ~ Sex, data = ecu_epi %>% filter(OutbreakBinary == "NotOutbreak2013", !is.na(Age)), exact = F, paired = F)

    Wilcoxon rank sum test with continuity correction

data:  Age by Sex
W = 56.5, p-value = 0.7716
alternative hypothesis: true location shift is not equal to 0

There was no significant difference in the ages of males or females who had P. falciparum cases after the outbreak (p = 0.77).

Was there a significant difference in the ages of males or females with P. falciparum cases during or after the outbreak?

wilcox.test(Age ~ Sex, data = ecu_epi %>% filter(!is.na(Age)), exact = F, paired = F)

    Wilcoxon rank sum test with continuity correction

data:  Age by Sex
W = 238, p-value = 0.5018
alternative hypothesis: true location shift is not equal to 0

There was no significant difference in the ages of males or females who had P. falciparum cases during or after the outbreak (p = 0.50).

Was there a significant difference in the ages of individuals with P. falciparum cases caused by the varcode1, a recombinant of varcode1 or a different varcode in 2013, 2014 and 2015?

There was no significant difference in the ages of individuals during/after the outbreak with clinical episodes caused by the outbreak varcode, a recombinant or a different varcode (p = 0.95, Kruskal-Wallis test).

The summary statistics for the ages of these individuals after the outbreak is:
OutbreakRecombinant min med avg max
DifferentVarcode 16 31 28.75000 37
OutbreakRecombinant 15 25 29.07143 58
OutbreakVarcode 19 19 31.66667 57

Was there a significant difference in the proportion of males and females with P. falciparum cases caused by the varcode1, a recombinant of varcode1 or a different varcode in 2014 and 2015?

ecu_epi %>% filter(OutbreakBinary != "Outbreak2013", !is.na(Age) & !is.na(Sex)) %>% group_by(OutbreakRecombinant) %>% tally()
ecu_epi %>% filter(OutbreakBinary != "Outbreak2013", !is.na(Age) & !is.na(Sex)) %>% group_by(OutbreakRecombinant, Sex) %>% tally()

x <- matrix(c(3, 4, 4, 7), nrow = 2)
y <- matrix(c(3, 4, 1, 2), nrow = 2)
z <- matrix(c(4, 7, 1, 2), nrow = 2)

chisq.test(x, correct = F)
chisq.test(y, correct = F)
chisq.test(z, correct = F)

ecu_epi %>% filter(OutbreakBinary != "Outbreak2013", !is.na(Age) & !is.na(Sex)) %>% group_by(OutbreakRecombinant, Sex) %>% tally() %>%
  ggplot(aes(x = OutbreakRecombinant)) + geom_bar(aes(y = n, fill = Sex), stat = "identity", position = "fill") 
ecu_epi %>% filter(!is.na(Age)) %>% 
  ggplot(aes(x = OutbreakBinary, y = Age)) + geom_boxplot() + geom_point() + stat_compare_means(method = "wilcox.test", paired = F)

ecu_epi %>% filter(!is.na(Age)) %>% 
  ggplot(aes(x = OutbreakBinary, y = Age)) + geom_boxplot() + geom_point() + facet_wrap(~Sex) + stat_compare_means(method = "wilcox.test", paired = F)

ecu_epi %>% filter(OutbreakBinary != "Outbreak2013", !is.na(Age)) %>% 
  ggplot(aes(x = OutbreakRecombinant, y = Age)) + geom_boxplot() + geom_point() + stat_compare_means(method = "kruskal.test", paired = F)

ecu_epi %>% filter(OutbreakBinary != "Outbreak2013", !is.na(Age)) %>% 
  ggplot(aes(x = OutbreakRecombinant, y = Age)) + geom_boxplot() + geom_point() + stat_compare_means(method = "kruskal.test", paired = F) + facet_wrap(~Sex)
LS0tCnRpdGxlOiAiRWN1YWRvciB2YXJjb2RlIHBhcGVyIGFuYWx5c2lzIgphdXRob3I6ICJTaGF6aWEgUnV5YmFsLVBlc2FudGV6IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBoaWRlIAogICAgZmlnX3dpZHRoOiA2CiAgICBmaWdfaGVpZ2h0OiA0CiAgICB0aGVtZTogY29zbW8KLS0tCmBgYHtyIGdsb2JhbF9vcHRpb25zLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLnBhdGggPSAidml6LyIsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gOCwgZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCB0aWR5ID0gVFJVRSkKYGBgCgojIyMgTGlicmFyaWVzIGFuZCBmdW5jdGlvbnMKTG9hZCB0aGUgbGlicmFyaWVzIHdlIHdpbGwgbmVlZCBmb3IgdGhlIGFuYWx5c2lzLgpgYGB7ciBzZXR1cCwgZWNobyA9IEZ9CmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShwbHlyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGFyc2VuYWwpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkodmVnYW4pCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShyZXNoYXBlKQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShlcGlSKQpsaWJyYXJ5KHRpYmJsZSkKbGlicmFyeShwdXJycikKbGlicmFyeShjb2xvcnRvb2xzKQpsaWJyYXJ5KE1hdHJpeCkKbGlicmFyeShnZ25ld3NjYWxlKQojbGlicmFyeShSVkFpZGVNZW1vaXJlKSAjI25vdCB3b3JraW5nCmxpYnJhcnkoaWdyYXBoKQpsaWJyYXJ5KHRpZHlncmFwaCkKbGlicmFyeShnZ3JhcGgpCmxpYnJhcnkoZ2dtYXApCmxpYnJhcnkoYXBlKQpsaWJyYXJ5KHJjb21wYW5pb24pCmxpYnJhcnkoZ2dhbmltYXRlKQpsaWJyYXJ5KGdpZnNraSkKbGlicmFyeShldWxlcnIpCmxpYnJhcnkoUnRzbmUpCiNCaW9jTWFuYWdlcjo6aW5zdGFsbCgiZ2d0cmVlIikKbGlicmFyeShnZ3RyZWUpCmxpYnJhcnkoZ2dzbikKbGlicmFyeShtYXBzKQpsaWJyYXJ5KG1hcGRhdGEpCmxpYnJhcnkoc2YpCmxpYnJhcnkocm5hdHVyYWxlYXJ0aCkKbGlicmFyeShybmF0dXJhbGVhcnRoZGF0YSkKbGlicmFyeShyZ2VvcykKbGlicmFyeShnZ3NwYXRpYWwpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShDYWlybykKbGlicmFyeShzdmdsaXRlKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHNjYXR0ZXJwaWUpCmBgYAoKTG9hZCBvdXIgZnVuY3Rpb25zLgpgYGB7ciBmdW5jdGlvbnN9CiNUaGlzIGZ1bmN0aW9uIGNhbGN1bGF0ZXMgUFRTIG9yIFBBUyBpbiB0aGUgY2FzZSBvZiBtaWNyb3NhdGVsbGl0ZXMuCnBhaXJ3aXNlVHlwZSA8LSBmdW5jdGlvbih4KXsKICAgIHggPC0gdCh4KQogICAgbW0gPC0gYXMoeCwgImRnQ01hdHJpeCIpCiAgICBkIDwtIHRjcm9zc3Byb2QobW0pCiAgICBkZW5vbSA8LSBtYXRyaXgocmVwKHJvd1N1bXMoeCksIG5jb2woZCkpLCBuY29sID0gbmNvbChkKSwgYnlyb3cgPSBGQUxTRSkKICAgIGRlbm9tIDwtIGRlbm9tICsgdChkZW5vbSkKICAgIHJldHVybihhcy5tYXRyaXgoMipkL2Rlbm9tKSkKfQoKI1RoaXMgZnVuY3Rpb24gY2FsY3VsYXRlcyBTaWogYW5kIFNqaSAoaS5lLiwgZGlyZWN0aW9uYWwgUFRTKSBhcyBpbiBIZSBldCBhbCAyMDE4LgpnZW5ldGljU2ltaWxhcml0eSA8LSBmdW5jdGlvbihtYXQpewogIG5ld21hdCA8LSB0Y3Jvc3Nwcm9kKG1hdCA+IDApCiAgbmV3bWF0IDwtIG5ld21hdC9yb3dTdW1zKG1hdCA+IDApCiAgcmV0dXJuKG5ld21hdCkgIAp9CgojVGhpcyBmdW5jdGlvbiBzYXZlcyB0aGUgUFRTIG1hdHJpeCB2YWx1ZXMgaW50byBhIHRhYmxlIGZvciBhbmFseXNpcyBwdXJwb3Nlcy4KUFRTbWF0cml4VG9UYWJsZSA8LSBmdW5jdGlvbih4KXsKICBkaWFnKHgpIDwtIE5BCiAgeFt1cHBlci50cmkoeCldIDwtIE5BCgogIGRmIDwtIGRhdGEuZnJhbWUoU2FtcGxlSUQxID0gcm93bmFtZXMoeClbcm93KHgpXSwgU2FtcGxlSUQyID0gY29sbmFtZXMoeClbY29sKHgpXSwgUFRTX3Njb3JlID0gYyh4KSkKICBkZiA8LSBuYS5vbWl0KGRmKQogIHJldHVybihkZikKfQoKI1RoaXMgZnVuY3Rpb24gc2F2ZXMgdGhlIEdlbmV0aWMgU2ltaWxhcml0eSBtYXRyaXggdmFsdWVzIGludG8gYSB0YWJsZSBmb3IgYW5hbHlzaXMgcHVycG9zZXMuIE5vdGUgdGhhdCB0aGVyZSBhcmUgdHdvIEdTIHNjb3JlcyBmb3IgZXZlcnkgaXNvbGF0ZSBwYWlyIChpLmUuIGRpcmVjdGlvbmFsIFBUUykKR1NtYXRyaXhUb1RhYmxlIDwtIGZ1bmN0aW9uKHgpewogIGRpYWcoeCkgPC0gTkEKCiAgZGYgPC0gZGF0YS5mcmFtZShTYW1wbGVJRDEgPSByb3duYW1lcyh4KVtyb3coeCldLCBTYW1wbGVJRDIgPSBjb2xuYW1lcyh4KVtjb2woeCldLCBHU19zY29yZSA9IGMoeCkpCiAgZGYgPC0gbmEub21pdChkZikKICByZXR1cm4oZGYpCn0KCiNUaGlzIGZ1bmN0aW9uIHNhdmVzIHRoZSBHZW5ldGljIFNpbWlsYXJpdHkgbWF0cml4IHZhbHVlcyBpbnRvIGEgdGFibGUgZm9yIGFuYWx5c2lzIHB1cnBvc2VzLiBOb3RlIHRoYXQgZm9yIHRoZSB2YXJjb2RlIGFuYWx5c2lzIHdlIG9ubHkgaW5jbHVkZSByZXRyb3NwZWN0aXZlIFBUUyBhbmQgd2Ugd2FudCB0byBpbmNsdWRlIHRoZSBkaWFnb25hbCBmb3IgdGhlICp2YXIqY29kZSBjb21wYXJpc29ucyAoaS5lLiB0aGUgMSkuCkdTbWF0cml4VG9UYWJsZV9WQyA8LSBmdW5jdGlvbih4KXsKICB4W3VwcGVyLnRyaSh4KV0gPC0gTkEKICBkZiA8LSBkYXRhLmZyYW1lKFNhbXBsZUlEMSA9IHJvd25hbWVzKHgpW3Jvdyh4KV0sIFNhbXBsZUlEMiA9IGNvbG5hbWVzKHgpW2NvbCh4KV0sIEdTX3Njb3JlID0gYyh4KSkKICBkZiA8LSBuYS5vbWl0KGRmKQogIHJldHVybihkZikKfQpgYGAKCiMjIyBMb2FkIGRhdGEKYGBge3J9CnVwcyA8LSBmcmVhZCgiZGF0YS9lY3VhZG9yX3Vwc19jbGFzc2lmaWNhdGlvbl9maW5hbC5jc3YiLCBkYXRhLnRhYmxlID0gRiwgKQpiaW5hcnlfYWxsIDwtIGZyZWFkKCJkYXRhL2VjdWFkb3JfU0FtX2JpbmFyeV9tYXRyaXhfZmluYWwuY3N2IiwgZGF0YS50YWJsZSA9IEYpCmJpbmFyeV9lY3UgPC0gZnJlYWQoImRhdGEvZWN1YWRvcl9iaW5hcnlfbWF0cml4X2ZpbmFsLmNzdiIsIGRhdGEudGFibGUgPSBGKQptaWNyb3NhdF9lY3UgPC0gZnJlYWQoImRhdGEvZWN1YWRvcl9iaW5hcnlfbWljcm9zYXRfZmluYWwuY3N2IiwgZGF0YS50YWJsZSA9IEYpCmVjdV9lcGkgPC0gZnJlYWQoImRhdGEvZWN1YWRvcl9lcGkuY3N2IiwgZGF0YS50YWJsZSA9IEYpCm91dGJyZWFrX21ldGFkYXRhIDwtIHJlYWQuY3N2KCJkYXRhL2VjdWFkb3JfdmFyY29kZTFfNDd0eXBlc19tZXRhZGF0YS5jc3YiKQpgYGAKCiMjIyBNYWtlIG1hdHJpY2VzCmBgYHtyfQptYXRyaXhfYWxsIDwtIGJpbmFyeV9hbGwKcm93bmFtZXMobWF0cml4X2FsbCkgPC0gbWF0cml4X2FsbCREQkxhX3R5cGUKbWF0cml4X2FsbCA8LSBtYXRyaXhfYWxsWywgLTFdCm1hdHJpeF9hbGwgPC0gYXMubWF0cml4KG1hdHJpeF9hbGwpCgplY3VfbWF0cml4IDwtIGJpbmFyeV9lY3UgCnJvd25hbWVzKGVjdV9tYXRyaXgpIDwtIGVjdV9tYXRyaXgkREJMYV90eXBlCmVjdV9tYXRyaXggPC0gZWN1X21hdHJpeFssIC0xXQplY3VfbWF0cml4IDwtIGFzLm1hdHJpeChlY3VfbWF0cml4KQpgYGAKCiMjIERCTM6xIHNhbXBsaW5nIGRlcHRoClRoZXJlIHdlcmUgYSB0b3RhbCBvZiBgciBucm93KGJpbmFyeV9lY3UpYCBEQkzOsSB0eXBlcyBhbmQgYHIgbmNvbChlY3VfbWF0cml4KWAgaXNvbGF0ZXMgaW4gRWN1YWRvci4KCiMjIyBIb3cgd2VsbCBoYXZlIHdlIHNhbXBsZWQgdGhlICp2YXIqIGRpdmVyc2l0eSBpbiBFY3VhZG9yPwpgYGB7ciBzYW1wbGluZyByYXJlZmFjdGlvbiBjdXJ2ZSBFY3VhZG9yLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0KZWN1X2N1cnZlIDwtIHNwZWNhY2N1bSh0KGVjdV9tYXRyaXgpLCBtZXRob2QgPSAicmFyZWZhY3Rpb24iKQpwbG90KGVjdV9jdXJ2ZSwgeHZhciA9ICJpbmRpdmlkdWFscyIsIGNpLnR5cGUgPSAicG9seWdvbiIsIHhsYWIgPSAiTnVtYmVyIG9mIERCTM6xIHNlcXVlbmNlcyBzYW1wbGVkIGluIEVjdWFkb3IiLCB5bGFiID0gIk51bWJlciBvZiBEQkzOsSB0eXBlcyBpZGVudGlmaWVkIGluIEVjdWFkb3IiKQojc2F2ZSB0aGlzIHZpYSBSc3R1ZGlvCmBgYAoKIyMjIEhvdyB3ZWxsIGhhdmUgd2Ugc2FtcGxlZCB0aGUgKnZhciogZGl2ZXJzaXR5IGluIFNvdXRoIEFtZXJpY2E/ICAKVGhlcmUgd2VyZSBhIHRvdGFsIG9mIGByIG5yb3coYmluYXJ5X2FsbClgIERCTM6xIHR5cGVzIGFuZCBgciBuY29sKG1hdHJpeF9hbGwpYCBpc29sYXRlcyBpbiBTb3V0aCBBbWVyaWNhLgpgYGB7ciBzYW1wbGluZyByYXJlZmFjdGlvbiBjdXJ2ZSBTQW19ClNBbV9jdXJ2ZSA8LSBzcGVjYWNjdW0odChtYXRyaXhfYWxsKSwgbWV0aG9kID0gInJhcmVmYWN0aW9uIikKcGxvdChTQW1fY3VydmUsIHh2YXIgPSAiaW5kaXZpZHVhbHMiLCBjaS50eXBlID0gInBvbHlnb24iLCB4bGFiID0gIk51bWJlciBvZiBEQkzOsSBzZXF1ZW5jZXMgc2FtcGxlZCBpbiBTb3V0aCBBbWVyaWNhIiwgeWxhYiA9ICJOdW1iZXIgb2YgREJMzrEgdHlwZXMgaWRlbnRpZmllZCBpbiBTb3V0aCBBbWVyaWNhIikKIyNzYXZlIHRoaXMgdmlhIFJzdHVkaW8KYGBgCgojIyBBcHBseWluZyB0aGUgKnZhcipjb2RlIHRvIGV4YW1pbmUgdHJhbnNtaXNzaW9uIHBhdHRlcm5zIGluIEVjdWFkb3IKIyMjIEdlbmV0aWMgc2ltaWxhcml0eTogY2FsY3VsYXRlIGRpcmVjdGlvbmFsIFBUUyAocmV0cm9zcGVjdGl2ZWx5KQpCZWNhdXNlIHdlIGFyZSBpbnRlcmVzdGVkIGluIGxvb2tpbmcgYXQgUFRTIG9yIGdlbmV0aWMgc2ltaWxhcml0eSBvZiBwYXJhc2l0ZXMgcmV0cm9zcGVjaXZlbHksIGkuZS4gd2hhdCBoYXBwZW5zICphZnRlciogdGhlIG91dGJyZWFrLCB3ZSB3aWxsIG9ubHkgZXhhbWluZSBwYWlyd2lzZSBjb21wYXJpc29ucyBvZiBpc29sYXRlcyByZXRyb3NwZWN0aXZlbHkuIFRoaXMgbWVhbnMgdGhhdCB3ZSB3aWxsIGNvbXBhcmUgaXNvbGF0ZXMgImJhY2t3YXJkcyIgdG8gaWRlbnRpZnkgaG93IHNpbWlsYXIgdGhleSBhcmUgdG8gdGhlIG91dGJyZWFrIGNsb25lLCBvciB0byBhbnl0aGluZyBlbHNlIGNpcmN1bGF0aW5nIGJlZm9yZSBpdHMgaWRlbnRpZmljYXRpb24uCmBgYHtyfQpnZW5TaW1fZWN1IDwtIGdlbmV0aWNTaW1pbGFyaXR5KHQoZWN1X21hdHJpeCkpCmdlblNpbV9lY3VbdXBwZXIudHJpKGdlblNpbV9lY3UpXSA8LSBOQQpHU3RhYmxlX2VjdSA8LSBHU21hdHJpeFRvVGFibGUoZ2VuU2ltX2VjdSkgCmBgYAoKIyMjIE1pY3Jvc2F0ZWxsaXRlczogUEFTCkhlcmUgd2Ugd2lsbCBwZXJmb3JtIGFuIGFuYWx5c2lzIG9mIHRoZSBtaWNyb3NhdGVsbGl0ZSBQQVMgZm9yIGV2ZXJ5IHNhbXBsZSBwYWlyLgoKKk5vdGUqIHRoYXQgZm9yIHRoZSBQQVMgY29tcGFyaXNvbnMgd2UgYWN0dWFsbHkgZG9uJ3QgbmVlZCB0aGUgR1MgZGlyZWN0aW9uYWwgUFRTIGZvciB0aGUgbWFqb3JpdHkgb2YgY29tcGFyaXNvbnMgYmVjYXVzZSB0aGUgZGVub21pbmF0b3IgaXMgdGhlIHNhbWUgLSBob3dldmVyLCB3ZSBkbyBoYXZlIE49MiBpc29sYXRlcyB3aXRoIDYgYWxsZWxlcyAoaS5lLiAxIGFsbGVsZSBtaXNzaW5nKSBhbmQgTj0xIGlzb2xhdGUgd2l0aCA1IGFsbGVsZXMgKGkuZS4gMiBtaXNzaW5nIGFsbGVsZXMpLCBzbyB3aWxsIHN0aWxsIGNhbGN1bGF0ZSBHUy4KYGBge3J9Cm1pY3Jvc2F0X2VjdSA8LSBtaWNyb3NhdF9lY3UgJT4lIGZpbHRlcihTYW1wbGVJRCAlaW4lIGVjdV9lcGkkU2FtcGxlSUQpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uX3RvX3Jvd25hbWVzKCJTYW1wbGVJRCIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KC1vbmVfb2YoYygiTVNfVEExMSIsICJNU18yNDkwMSIsICJNU19DMk0zNDEiLCAiTVNfQzNNNjkxIikpKQoKbWljcm9zYXRfUEFTIDwtIGdlbmV0aWNTaW1pbGFyaXR5KG1pY3Jvc2F0X2VjdSkKbWljcm9zYXRfUEFTW3VwcGVyLnRyaShtaWNyb3NhdF9QQVMpXSA8LSBOQQpQQVN0YWJsZV9lY3VNUyA8LSBHU21hdHJpeFRvVGFibGUobWljcm9zYXRfUEFTKQpgYGAKCiMjIyBQVFMgdnMgUEFTCldlIGNhbiBub3cgY29tcGFyZSB0aGUgUFRTIGFuZCBQQVMgdmFsdWVzIGZvciBlYWNoIHBhaXJ3aXNlIGNvbXBhcmlzb24gKHJldHJvc3BlY3RpdmVseSkgYnkgbWF0Y2hpbmcgdGhlIG1pY3Jvc2F0IHBhaXJ3aXNlIGNvbXBhcmlzb25zIFNhbXBsZUlEMS1TYW1wbGVJRDIgd2l0aCAqdmFyKiBlbmFibGluZyBhIGRpcmVjdCBjb21wYXJpc29uLiAKCldlIGFyZSBpbnRlcmVzdGVkIGluIGxvb2tpbmcgYXQ6IGhvdyBjb3JyZWxhdGVkIGFyZSBwcmVkaWN0aW9ucyBvZiByZWNvbWJpbmFudHMgYnkgKnZhciogY29tcGFyZWQgdG8gTVM/ICAKYGBge3IgY3JlYXRlIHRhYmxlIHdpdGggUFRTIGFuZCBQQVN9CkdTdGFibGVfZWN1X3Zhck1TIDwtIEdTdGFibGVfZWN1ICU+JSBsZWZ0X2pvaW4oUEFTdGFibGVfZWN1TVMsIGJ5ID0gYygiU2FtcGxlSUQxIiwgIlNhbXBsZUlEMiIpKQpHU3RhYmxlX2VjdV92YXJNUyA8LSBHU3RhYmxlX2VjdV92YXJNUyAlPiUgcmVuYW1lX2F0KCJHU19zY29yZS54IiwgfiJQVFNfc2NvcmUiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW5hbWVfYXQoIkdTX3Njb3JlLnkiLCB+IlBBU19zY29yZSIpIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCmNvcnJlbGF0aW9uX3Bsb3QgPC0gR1N0YWJsZV9lY3VfdmFyTVMgJT4lCiAgIGdncGxvdChhZXMoeCA9IFBUU19zY29yZSwgeSA9IFBBU19zY29yZSkpICsgCiAgICAgIGdlb21faml0dGVyKHNoYXBlID0gMjEsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDIpICsKICAgICAgI3N0YXRfc21vb3RoX2Z1bmMoZ2VvbSA9ICJ0ZXh0IiwgbWV0aG9kID0gImxtIiwgaGp1c3QgPSAwLCBwYXJzZSA9IFQpICsKICAgICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBULCBjb2xvciA9ICJkYXJrZ3JleSIpICsKICAgICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxLCBieSA9IDAuMjUpKSArIAogICAgICB0aGVtZV9jb3dwbG90KCkgKwogICAgICB5bGFiKGV4cHJlc3Npb24ocGFzdGUoIlAiWyJBUyJdLCAiIHNjb3JlIikpKSArCiAgICAgIHhsYWIoZXhwcmVzc2lvbihwYXN0ZSgiUCJbIlRTIl0sICIgc2NvcmUiKSkpICsKICAgICAgYmFja2dyb3VuZF9ncmlkKG1ham9yID0gInh5IiwgbWlub3IgPSAibm9uZSIpIAoKY29yLnRlc3QoR1N0YWJsZV9lY3VfdmFyTVMkUFRTX3Njb3JlLCBHU3RhYmxlX2VjdV92YXJNUyRQQVNfc2NvcmUsIG1ldGhvZCA9IGMoInBlYXJzb24iKSkKc2F2ZV9wbG90KCJ2aXovY29ycmVsYXRpb25fUFRTdlBBUy5wbmciLCBjb3JyZWxhdGlvbl9wbG90LCBiYXNlX3dpZHRoID0gOCwgYmFzZV9oZWlnaHQgPSA2KQpjb3JyZWxhdGlvbl9wbG90CmBgYApUaGVyZSB3ZXJlIGEgdG90YWwgb2YgYHIgR1N0YWJsZV9lY3VfdmFyTVMgJT4lIGZpbHRlcihQQVNfc2NvcmUgPT0gMSAmIFBUU19zY29yZSA8PSAwLjUwKSAlPiUgbnJvdygpYCAoYHIgY2VpbGluZygoR1N0YWJsZV9lY3VfdmFyTVMgJT4lIGZpbHRlcihQQVNfc2NvcmUgPT0gMSAmIFBUU19zY29yZSA8PSAwLjUwKSAlPiUgbnJvdygpKS8oR1N0YWJsZV9lY3VfdmFyTVMgJT4lIGZpbHRlcihQQVNfc2NvcmUgPT0gMSkgJT4lIG5yb3coKSkqMTAwKWAlKSBvdXQgb2YgYHIgR1N0YWJsZV9lY3VfdmFyTVMgJT4lIGZpbHRlcihQQVNfc2NvcmUgPT0gMSkgJT4lIG5yb3coKWAgcGFpcndpc2UgY29tcGFyaXNvbnMgd2hlcmUgUEFTPTEgYnV0IFBUUyDiiaQwLjUwLiAKClRoZXJlIHdlcmUgYSB0b3RhbCBvZiBgciBHU3RhYmxlX2VjdV92YXJNUyAlPiUgZmlsdGVyKFBBU19zY29yZSA+IDAuNTAgJiBQVFNfc2NvcmUgPD0gMC41MCkgJT4lIG5yb3coKWAgKGByIGNlaWxpbmcoKEdTdGFibGVfZWN1X3Zhck1TICU+JSBmaWx0ZXIoUEFTX3Njb3JlID4gMC41MCAmIFBUU19zY29yZSA8PSAwLjUwKSAlPiUgbnJvdygpKS8oR1N0YWJsZV9lY3VfdmFyTVMgJT4lIGZpbHRlcihQQVNfc2NvcmUgPiAwLjUwKSAlPiUgbnJvdygpKSoxMDApYCUpIG91dCBvZiBgciBHU3RhYmxlX2VjdV92YXJNUyAlPiUgZmlsdGVyKFBBU19zY29yZSA+IDAuNTApICU+JSBucm93KClgIHBhaXJ3aXNlIGNvbXBhcmlzb25zIHdoZXJlIFBBUz4wLjUwIGJ1dCBQVFMg4omkMC41MC4gCgojIyBOZXR3b3JrIEFuYWx5c2lzOiAqdmFyKgojIyMgVmlzdWFsaXppbmcgZ2VuZXRpYyBzaW1pbGFyaXR5IG5ldHdvcmsgKFBUUykgdXNpbmcgdGlkeWdyYXBoL2dncmFwaApOb3cgd2Ugd2FudCB0byBleGFtaW5lIHRoZSByZWxhdGlvbnNoaXBzIGFtb25nIHJlcGVydG9pcmVzIGJ5IHZpc3VhbGl6aW5nIHRoZSByZXRyb3NwZWN0aXZlIFBUUyB2YWx1ZXMgaW4gYSBuZXR3b3JrLiAKCkZvciBmdXR1cmUgcmVmZXJlbmNlIEkgYW0gYnVpbGRpbmcgdGhlIG5ldHdvcmsgYnkgZm9sbG93aW5nIHRoZSBndWlkZWxpbmVzIGZyb20gdGhpcyBbdHV0b3JpYWxdKGh0dHBzOi8vc2hpcmluc3BsYXlncm91bmQubmV0bGlmeS5jb20vMjAxOC8wMy9nb3RfbmV0d29yay8/dXRtX2NhbXBhaWduPU5ld3MmdXRtX21lZGl1bT1Db21tdW5pdHkmdXRtX3NvdXJjZT1EYXRhQ2FtcC5jb20pKSBhbmQgdGhpcyBbdHV0b3JpYWxdKGh0dHBzOi8vd3d3Lmplc3Nlc2FkbGVyLmNvbS9wb3N0L25ldHdvcmstYW5hbHlzaXMtd2l0aC1yLykuIEkgd2lsbCBidWlsZCB0aGUgbmV0d29yayB1c2luZyBnZyBzeW50YXggKGkuZS4gc2ltaWxhciB0byBnZ3Bsb3Qgc3ludGF4KSB1c2luZyB0aGUgcGFja2FnZXMgYGdncmFwaGAgYW5kIGB0aWR5Z3JhcGhgLiAgCgpGaXJzdCB3ZSBuZWVkIHRvIHNhdmUgb3VyIGRhdGEgaW4gdGhlIHByb3BlciBmb3JtYXQgdG8gYnVpbGQgdGhlIG5ldHdvcmsuIFRoZSBgR1N0YWJsZV9lY3VgIGJlY29tZXMgb3VyIGBlZGdlc2AgZGF0YXNldCwgYW5kIHRoZSBlcGkgZGF0YSBiZWNvbWVzIG91ciBgbm9kZXNgIGRhdGFzZXQuICpOb3RlKjogbWFrZSBzdXJlIHRvIHVzZSB0aGUgZm9sbG93aW5nIGNvZGUgdG8gY3JlYXRlIHRoZSBgZWRnZXNgIChpLmUuIGFzc2lnbmluZyBpZCksIGlmIG5vdCB0aGUgUFRTIGVkZ2VzIGJldHdlZW4gaXNvbGF0ZXMgbWF5IGJlIHdyb25nLiBUaGlzIHdheSB3ZSBlbnN1cmUgdGhhdCB0aGUgaWQueCBhbmQgaWQueSBvZiBlYWNoIGVkZ2UgY29ycmVzcG9uZHMgdG8gdGhlaXIgYWN0dWFsIFNhbXBsZUlEIGluIHRoZSBub2RlcyBkYXRhc2V0LiAgCgpgYGB7ciB0aWR5Z3JhcGggZm9yIGVjdWFkb3IgbmV0d29ya30KZWN1X2VkZ2VzIDwtIEdTdGFibGVfZWN1ICU+JSBsZWZ0X2pvaW4oZWN1X2VwaSwgYnkgPSBjKCJTYW1wbGVJRDEiID0gIlNhbXBsZUlEIikpICU+JSByZW5hbWUoaWQueCA9IGlkKQplY3VfZWRnZXMgPC0gZWN1X2VkZ2VzICU+JSBsZWZ0X2pvaW4oZWN1X2VwaSwgYnkgPSBjKCJTYW1wbGVJRDIiID0gIlNhbXBsZUlEIikpICU+JSByZW5hbWUoaWQueSA9IGlkKQplY3VfZWRnZXMgPC0gZWN1X2VkZ2VzICU+JSBzZWxlY3QoaWQueCwgaWQueSwgR1Nfc2NvcmUpCgplY3VfdGlkeSA8LSB0YmxfZ3JhcGgobm9kZXMgPSBlY3VfZXBpLCBlZGdlcyA9IGVjdV9lZGdlcywgZGlyZWN0ZWQgPSBUKQpgYGAKVGhlIHRpYmJsZSBgdGlkeV9ncmFwaGAgb2JqZWN0IGNvbnNpc3RzIG9mIGJvdGggYGVkZ2VzYCBhbmQgYG5vZGVzYCwgZWl0aGVyIG9mIHdoaWNoIGNhbiBiZSBhY3RpdmF0ZWQgZGVwZW5kaW5nIG9uIHdoYXQgd2UgbmVlZCB0byBkby4gCgojIyMjIERlZmluaW5nICp2YXIqY29kZXMgKFBUUyA+PSAwLjkpCmBgYHtyfQp2YXJjb2RlX2xpc3QgPC0gZWN1X2VwaSAlPiUgc2VsZWN0KFNhbXBsZUlELCB2YXJjb2RlKQp2YXJjb2RlX2xpc3QkU2FtcGxlSUQgPC0gYXMuZmFjdG9yKHZhcmNvZGVfbGlzdCRTYW1wbGVJRCkKdmFyY29kZV9saXN0JHZhcmNvZGUgPC0gYXMuZmFjdG9yKHZhcmNvZGVfbGlzdCR2YXJjb2RlKQp2YXJjb2RlX2xpc3QgPC0gdmFyY29kZV9saXN0ICU+JSBjb2x1bW5fdG9fcm93bmFtZXMoIlNhbXBsZUlEIikKdmFyY29kZV9jb2xvcnMgPC0gbGlzdCh2YXJjb2RlID0gYygidmFyY29kZTEiID0gIiNmYjlhOTkiLCAidmFyY29kZTIiID0gIiNlNTM4YTkiLCJ2YXJjb2RlMyIgPSAiIzQ4QjI0RiIsICJ2YXJjb2RlNCIgPSAiIzMwZDVjOCIsICJ2YXJjb2RlNSIgPSAiI0U0QjAzMSIsICJ2YXJjb2RlNiIgPSAiIzMwOTBkNSIsICJ2YXJjb2RlNyIgPSAiI0NBRDkzRiIsICJ2YXJjb2RlOCIgPSAiIzlhYzRiMyIsICJ2YXJjb2RlOSIgPSAiI2E4ODBiYiIpKQoKZWN1X3ZhcmNvZGVzX25ldHdvcmsgPC0gZWN1X3RpZHkgJT4lIGFjdGl2YXRlKGVkZ2VzKSAlPiUgZmlsdGVyKEdTX3Njb3JlID49IDAuOSkgJT4lIAogIGdncmFwaChsYXlvdXQgPSAiZnIiKSArIAogIGdlb21fZWRnZV9saW5rKGNvbG9yID0gImRhcmtncmV5IiwgYWxwaGEgPSAwLjUpICsgCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhmaWxsID0gdmFyY29kZSksIHNoYXBlID0gMjEsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDQpICsKICAjZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gU2FtcGxlSUQpLCByZXBlbCA9IFRSVUUpICsKICBsYWJzKGVkZ2Vfd2lkdGggPSAiU2FtcGxlSUQiLAogICAgICAgZmlsbCA9ICIiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gdmFyY29kZV9jb2xvcnMkdmFyY29kZSwgbGFiZWxzID0gYygidmFyY29kZTEgKE49MzYpIiwgInZhcmNvZGUyIChOPTMpIiwgInZhcmNvZGUzIChOPTMpIiwgInZhcmNvZGU0IChOPTEpIiwgInZhcmNvZGU1IChOPTEpIiwgInZhcmNvZGU2IChOPTMpIiwgInZhcmNvZGU3IChOPTgpIiwgInZhcmNvZGU4IChOPTIpIiwgInZhcmNvZGU5IChOPTEpIikpICsKICB0aGVtZV9ncmFwaCgpCgpzYXZlX3Bsb3QoInZpei9lY3VhZG9yX3ZhcmNvZGVfbmV0d29yay5wbmciLCBlY3VfdmFyY29kZXNfbmV0d29yaywgYmFzZV93aWR0aCA9IDgsIGJhc2VfaGVpZ2h0ID0gNikKZWN1X3ZhcmNvZGVzX25ldHdvcmsKYGBgCldlIGlkZW50aWZ5IDkgKnZhcipjb2RlcyBpbiBFY3VhZG9yLiAqTm90ZSo6IEVDUGYwMDQgYW5kIEVDUGYwMTEgYXJlIHVuZGVyc2FtcGxlZCwgYW5kIGJlbG9uZyB0byAqdmFyKmNvZGUxLiBUaGUgbnVtYmVyIG9mIGlzb2xhdGVzIGdyb3VwZWQgaW4gZWFjaCAqdmFyKmNvZGUgaXM6IGByIGtuaXRyOjprYWJsZShlY3VfZXBpICU+JSBncm91cF9ieSh2YXJjb2RlKSAlPiUgdGFsbHkoKSkgJT4lIGthYmxlX3N0eWxpbmcoKWAKCiMjIyMgSG93IG1hbnkgKnZhcipjb2RlcyB3ZXJlIHRoZXJlIGluIGVhY2ggdGltZXBvaW50PwpgYGB7cn0KdGltZXBvaW50cyA8LSBjKCIyMDEzIiwgIjIwMTQiLCAiMjAxNSIpCnRvdGFsbnVtX3ZhcmNvZGVzIDwtIGMoIjMiLCAiOCIsICI0IikKdmFyY29kZXNfYnl0aW1lIDwtIGRhdGEuZnJhbWUodGltZXBvaW50cywgdG90YWxudW1fdmFyY29kZXMpCmBgYApUaGUgbnVtYmVyIG9mICp2YXIqY29kZXMgaWRlbnRpZmllZCBpbiBlYWNoIHRpbWVwb2ludCB3YXMgYXMgZm9sbG93czogYHIga2FibGUodmFyY29kZXNfYnl0aW1lKSAlPiUga2FibGVfc3R5bGluZygpYC4KCiMjIyMgSG93IGRvICp2YXIqY29kZXMgcGVyc2lzdCBpbiB0aW1lPwpgYGB7cn0KdmFyY29kZSA8LSBjKCJ2YXJjb2RlMSIsICJ2YXJjb2RlMiIsICJ2YXJjb2RlMyIsICJ2YXJjb2RlNiIsICJ2YXJjb2RlNyIsICJ2YXJjb2RlOCIsICJ2YXJjb2RlNCIsICJ2YXJjb2RlNSIsICJ2YXJjb2RlOSIpCnZjMjAxMyA8LSBjKDMwLCAyLCAxLCBOQSwgTkEsIE5BLCBOQSwgTkEsIE5BKQp2YzIwMTQgPC0gYyg0LCAxLCAyLCAyLCA2LCAyLCAxLCAxLCBOQSkKdmMyMDE1IDwtIGMoMiwgTkEsIE5BLCAxLCAyLCBOQSwgTkEsIE5BLCAxKQp2YXJjb2Rlc190ZW1wb3JhbCA8LSBkYXRhLmZyYW1lKHZhcmNvZGUsIHZjMjAxMywgdmMyMDE0LCB2YzIwMTUpCnZhcmNvZGVzX3RlbXBvcmFsIDwtIHZhcmNvZGVzX3RlbXBvcmFsICU+JSByZW5hbWVfYXQoInZjMjAxMyIsIH4iMjAxMyIpICU+JSByZW5hbWVfYXQoInZjMjAxNCIsIH4iMjAxNCIpICU+JSByZW5hbWVfYXQoInZjMjAxNSIsIH4iMjAxNSIpCgp2YXJjb2Rlc190aW1lbGluZSA8LSB2YXJjb2Rlc190ZW1wb3JhbCAlPiUgCiAgbWVsdChpZC52YXIgPSAidmFyY29kZSIpICU+JSAKICByZW5hbWVfYXQoInZhcmlhYmxlIiwgfiJZZWFyIikgJT4lIAogIHJlbmFtZV9hdCgidmFsdWUiLCB+IkZyZXF1ZW5jeSIpICU+JSAKICBtdXRhdGUodmFyY29kZSA9IGZhY3Rvcih2YXJjb2RlLCBsZXZlbHMgPSBjKCJ2YXJjb2RlOSIsICJ2YXJjb2RlOCIsICJ2YXJjb2RlNyIsICJ2YXJjb2RlNiIsICJ2YXJjb2RlNSIsICJ2YXJjb2RlNCIsICJ2YXJjb2RlMyIsICJ2YXJjb2RlMiIsICJ2YXJjb2RlMSIpKSkgJT4lIAogIGdncGxvdChhZXMoWWVhciwgZmFjdG9yKHZhcmNvZGUpKSkgKyAKICAgICAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IEZyZXF1ZW5jeSwgY29sb3IgPSB2YXJjb2RlKSkgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gRnJlcXVlbmN5KSwgc2l6ZSA9IDIuNSwgdmp1c3QgPSAxLjUsIGhqdXN0ID0gLTEpICsKICAgICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKG5hbWUgPSAiTnVtYmVyIG9mIFBmIGlzb2xhdGVzIiwKICAgICAgICAgICAgIGJyZWFrcyA9IGMoMSwgMTAsIDMwKSwKICAgICAgICAgICAgIGxhYmVscyA9IGMoIjEiLCAiMTAiLCAiMzAiKSkgKwogICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gdmFyY29kZV9jb2xvcnMkdmFyY29kZSwgbGFiZWxzID0gdmFyY29kZV9saXN0KSArCiAgICAgIGFubm90YXRlKCJzZWdtZW50IiwgeCA9IDEsIHhlbmQgPSAzLCB5ID0gOSwgeWVuZCA9IDksIGNvbG91ciA9ICIjZmI5YTk5IikgKwogICAgICBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAxLCB4ZW5kID0gMiwgeSA9IDgsIHllbmQgPSA4LCBjb2xvdXIgPSAiI2U1MzhhOSIpICsKICAgICAgYW5ub3RhdGUoInNlZ21lbnQiLCB4ID0gMSwgeGVuZCA9IDIsIHkgPSA3LCB5ZW5kID0gNywgY29sb3VyID0gIiM0OEIyNEYiKSArCiAgICAgIGFubm90YXRlKCJzZWdtZW50IiwgeCA9IDIsIHhlbmQgPSAzLCB5ID0gNCwgeWVuZCA9IDQsIGNvbG91ciA9ICIjMzA5MGQ1IikgKwogICAgICBhbm5vdGF0ZSgic2VnbWVudCIsIHggPSAyLCB4ZW5kID0gMywgeSA9IDMsIHllbmQgPSAzLCBjb2xvdXIgPSAiI0NBRDkzRiIpICsgIAogICAgICB5bGFiKCIiKSArCiAgICAgIHRoZW1lX2J3KCkgCgpzYXZlX3Bsb3QoInZpei92YXJjb2Rlc190aW1lbGluZS5wbmciLCB2YXJjb2Rlc190aW1lbGluZSkKdmFyY29kZXNfdGltZWxpbmUKYGBgCgojIyMgRHVyYXRpb24gb2YgKnZhcipjb2RlIHBlcnNpc3RlbmNlCk5vdyB3ZSBjYW4gY2FsY3VsYXRlIHRoZSBhdmVyYWdlIGRheXMgYSAqdmFyKmNvZGUgcGVyc2lzdGVkLiAKYGBge3IgZHVyYXRpb24gb2YgcGVyc2lzdGFuY2V9CmVjdV9lcGkkRGF0ZUNvbGxlY3RlZCA8LSBhcy5EYXRlKGVjdV9lcGkkRGF0ZUNvbGxlY3RlZCkKCiNlY3VfZXBpICU+JSBmaWx0ZXIoU2FtcGxlSUQgPT0gIkVDUGYwMDMiIHwgU2FtcGxlSUQgPT0gIkVDUGYwNzYiKSAlPiUgc2VsZWN0KHZhcmNvZGUsIERhdGVDb2xsZWN0ZWQpIAoKdmMxX2R1cmF0aW9uIDwtIGRhdGEuZnJhbWUodmFyY29kZSA9ICJ2YXJjb2RlMSIsIEZpcnN0SUQgPSBzdWJzZXQoZWN1X2VwaSwgU2FtcGxlSUQgPT0gIkVDUGYwMDMiKSREYXRlQ29sbGVjdGVkLCBMYXN0SUQgPSBzdWJzZXQoZWN1X2VwaSwgU2FtcGxlSUQgPT0gIkVDUGYwNzYiKSREYXRlQ29sbGVjdGVkKSAKCnZjMl9kdXJhdGlvbiA8LSBkYXRhLmZyYW1lKHZhcmNvZGUgPSAidmFyY29kZTIiLCBGaXJzdElEID0gc3Vic2V0KGVjdV9lcGksIFNhbXBsZUlEID09ICJFQ1BmMDI0IikkRGF0ZUNvbGxlY3RlZCwgTGFzdElEID0gc3Vic2V0KGVjdV9lcGksIFNhbXBsZUlEID09ICJFQ1BmMDQ1IikkRGF0ZUNvbGxlY3RlZCkgCgp2YzNfZHVyYXRpb24gPC0gZGF0YS5mcmFtZSh2YXJjb2RlID0gInZhcmNvZGUzIiwgRmlyc3RJRCA9IHN1YnNldChlY3VfZXBpLCBTYW1wbGVJRCA9PSAiRUNQZjAzNSIpJERhdGVDb2xsZWN0ZWQsIExhc3RJRCA9IHN1YnNldChlY3VfZXBpLCBTYW1wbGVJRCA9PSAiRUNQZjA1MyIpJERhdGVDb2xsZWN0ZWQpIAoKdmM2X2R1cmF0aW9uIDwtIGRhdGEuZnJhbWUodmFyY29kZSA9ICJ2YXJjb2RlNiIsIEZpcnN0SUQgPSBzdWJzZXQoZWN1X2VwaSwgU2FtcGxlSUQgPT0gIkVDUGYwNTEiKSREYXRlQ29sbGVjdGVkLCBMYXN0SUQgPSBzdWJzZXQoZWN1X2VwaSwgU2FtcGxlSUQgPT0gIkVDUGYwNzIiKSREYXRlQ29sbGVjdGVkKSAKCnZjN19kdXJhdGlvbiA8LSBkYXRhLmZyYW1lKHZhcmNvZGUgPSAidmFyY29kZTciLCBGaXJzdElEID0gc3Vic2V0KGVjdV9lcGksIFNhbXBsZUlEID09ICJFQ1BmMDU2IikkRGF0ZUNvbGxlY3RlZCwgTGFzdElEID0gc3Vic2V0KGVjdV9lcGksIFNhbXBsZUlEID09ICJFQ1BmMDY3IikkRGF0ZUNvbGxlY3RlZCkgCgp2Y19kdXJhdGlvbiA8LSBiaW5kX3Jvd3ModmMxX2R1cmF0aW9uLCB2YzJfZHVyYXRpb24sIHZjM19kdXJhdGlvbiwgdmM2X2R1cmF0aW9uLCB2YzdfZHVyYXRpb24pCgp2Y19kdXJhdGlvbiA8LSB2Y19kdXJhdGlvbiAlPiUgbXV0YXRlKGR1cmF0aW9uX2RheXMgPSBkaWZmdGltZShMYXN0SUQsIEZpcnN0SUQsIHVuaXRzID0gYygiZGF5cyIpKSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGR1cmF0aW9uX3lyID0gcm91bmQoZHVyYXRpb25fZGF5cy8zNjUsIDIpKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZHVyYXRpb25fbW9udGhzID0gcm91bmQoZHVyYXRpb25feXIqMTIsIDIpKQpgYGAKVGhlICp2YXIqY29kZXMgcGVyc2lzdGVkIGZvciB0aGUgZm9sbG93aW5nIGFtb3VudCBvZiB0aW1lOiBgciBrbml0cjo6a2FibGUodmNfZHVyYXRpb24pICU+JSBrYWJsZV9zdHlsaW5nKClgCgpUaGUgc3VtbWFyeSBzdGF0aXN0aWNzIGZvciB0aGUgZHVyYXRpb24gb2YgZWFjaCAqdmFyKmNvZGUgIGluIGRheXMgd2FzOiBgciBrbml0cjo6a2FibGUodmNfZHVyYXRpb24gJT4lIHN1bW1hcml6ZShtaW5fZGF5cyA9IG1pbihkdXJhdGlvbl9kYXlzKSwgbWVkX2RheXMgPSBtZWRpYW4oZHVyYXRpb25fZGF5cyksIGF2Z19kYXlzID0gbWVhbihkdXJhdGlvbl9kYXlzKSwgbWF4X2RheXMgPSBtYXgoZHVyYXRpb25fZGF5cykpKSAlPiUga2FibGVfc3R5bGluZygpYCAKClRoZSBzdW1tYXJ5IHN0YXRpc3RpY3MgZm9yIHRoZSBkdXJhdGlvbiBvZiBlYWNoICp2YXIqY29kZSBpbiBtb250aHMgd2FzOiBgciBrbml0cjo6a2FibGUodmNfZHVyYXRpb24gJT4lIHN1bW1hcml6ZShtaW5fbW9udGhzID0gbWluKGR1cmF0aW9uX21vbnRocyksIG1lZF9tb250aHMgPSBtZWRpYW4oZHVyYXRpb25fbW9udGhzKSwgYXZnX21vbnRocyA9IG1lYW4oZHVyYXRpb25fbW9udGhzKSwgbWF4X21vbnRocyA9IG1heChkdXJhdGlvbl9tb250aHMpKSkgJT4lIGthYmxlX3N0eWxpbmcoKWAgCgpUaGUgc3VtbWFyeSBzdGF0aXN0aWNzIGZvciB0aGUgZHVyYXRpb24gb2YgZWFjaCAqdmFyKmNvZGUgaW4geWVhcnMgd2FzOiBgciBrbml0cjo6a2FibGUodmNfZHVyYXRpb24gJT4lIHN1bW1hcml6ZShtaW5feXIgPSBtaW4oZHVyYXRpb25feXIpLCBtZWRfeXIgPSBtZWRpYW4oZHVyYXRpb25feXIpLCBhdmdfeXIgPSBtZWFuKGR1cmF0aW9uX3lyKSwgbWF4X3lyID0gbWF4KGR1cmF0aW9uX3lyKSkpICU+JSBrYWJsZV9zdHlsaW5nKClgIAoKIyMjIyBEZWZpbmluZyAqdmFyKmNvZGVzIGluIFNhbiBMb3JlbnpvIChQVFMgPj0gMC45KQpgYGB7cn0KZWN1X3RpZHkgJT4lIGFjdGl2YXRlKG5vZGVzKSAlPiUgZmlsdGVyKExvY2F0aW9uQ29kZSA9PSAiU2FuIExvcmVuem8sIEVzbWVyYWxkYXMiKSAlPiUgCiAgYWN0aXZhdGUoZWRnZXMpICU+JSBmaWx0ZXIoR1Nfc2NvcmUgPj0gMC45KSAlPiUgCiAgZ2dyYXBoKGxheW91dCA9ICJmciIpICsgCiAgZ2VvbV9lZGdlX2xpbmsoY29sb3IgPSAiZGFya2dyZXkiLCBhbHBoYSA9IDAuNSkgKyAKICBnZW9tX25vZGVfcG9pbnQoYWVzKGZpbGwgPSB2YXJjb2RlKSwgc2hhcGUgPSAyMSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gNCkgKwogICNnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBTYW1wbGVJRCksIHJlcGVsID0gVFJVRSkgKwogIGxhYnMoZWRnZV93aWR0aCA9ICJTYW1wbGVJRCIsCiAgICAgICBmaWxsID0gIiIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB2YXJjb2RlX2NvbG9ycyR2YXJjb2RlKSArCiAgdGhlbWVfZ3JhcGgoKQpgYGAKCiMjIyMgSWRlbnRpZnlpbmcgcmVjb21iaW5hbnRzOiB0cmFuc21pc3Npb24gbmV0d29yayAqdmFyKmNvZGVzIChQVFMgPj0gMC41KQpgYGB7cn0KZWN1YWRvcl9yZWNvbWJpbmFudHNfbmV0d29yayA8LSBlY3VfdGlkeSAlPiUgYWN0aXZhdGUoZWRnZXMpICU+JSBmaWx0ZXIoR1Nfc2NvcmUgPj0gMC41KSAlPiUgCiAgZ2dyYXBoKGxheW91dCA9ICJmciIpICsgCiAgZ2VvbV9lZGdlX2xpbmsoY29sb3IgPSAiZGFya2dyZXkiLCBhbHBoYSA9IDAuNSkgKyAKICBnZW9tX25vZGVfcG9pbnQoYWVzKGZpbGwgPSB2YXJjb2RlKSwgc2hhcGUgPSAyMSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gNCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHZhcmNvZGVfY29sb3JzJHZhcmNvZGUsIGxhYmVscyA9IHZhcmNvZGVfbGlzdCkgKwogICNnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBTYW1wbGVJRCksIHJlcGVsID0gVFJVRSkgKwogIGxhYnMoZWRnZV93aWR0aCA9ICJTYW1wbGVJRCIpICsKICB0aGVtZV9ncmFwaCgpCgpzYXZlX3Bsb3QoInZpei9lY3VhZG9yX3JlY29tYmluYW50c19uZXR3b3JrLnBuZyIsIGVjdWFkb3JfcmVjb21iaW5hbnRzX25ldHdvcmssIGJhc2Vfd2lkdGggPSA4LCBiYXNlX2hlaWdodCA9IDYpCmVjdWFkb3JfcmVjb21iaW5hbnRzX25ldHdvcmsKYGBgCgojIyBOZXR3b3JrIGFuYWx5c2lzOiBtaWNyb3NhdGVsbGl0ZXMKYGBge3J9CmVjdU1TZWRnZXMgPC0gUEFTdGFibGVfZWN1TVMgJT4lIGxlZnRfam9pbihlY3VfZXBpLCBieSA9IGMoIlNhbXBsZUlEMSIgPSAiU2FtcGxlSUQiKSkgJT4lIHJlbmFtZShpZC54ID0gaWQpCmVjdU1TZWRnZXMgPC0gZWN1TVNlZGdlcyAlPiUgbGVmdF9qb2luKGVjdV9lcGksIGJ5ID0gYygiU2FtcGxlSUQyIiA9ICJTYW1wbGVJRCIpKSAlPiUgcmVuYW1lKGlkLnkgPSBpZCkKZWN1TVNlZGdlcyA8LSBlY3VNU2VkZ2VzICU+JSBzZWxlY3QoaWQueCwgaWQueSwgR1Nfc2NvcmUpCgplY3VNU190aWR5IDwtIHRibF9ncmFwaChub2RlcyA9IGVjdV9lcGksIGVkZ2VzID0gZWN1TVNlZGdlcywgZGlyZWN0ZWQgPSBUKQpgYGAKCiMjIyBEZWZpbmluZyBjbG9uZXMgYnkgTVMKYGBge3J9CmVjdWFkb3JfTVNjbHVzdGVyc19uZXR3b3JrIDwtIGVjdU1TX3RpZHkgJT4lIGFjdGl2YXRlKGVkZ2VzKSAlPiUgZmlsdGVyKEdTX3Njb3JlID49IDAuOTApICU+JSAKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKyAKICBnZW9tX2VkZ2VfbGluayhjb2xvciA9ICJkYXJrZ3JleSIsIGFscGhhID0gMC41KSArIAogIGdlb21fbm9kZV9wb2ludChhZXMoZmlsbCA9IHZhcmNvZGUpLCBzaGFwZSA9IDIxLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSA0KSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gdmFyY29kZV9jb2xvcnMkdmFyY29kZSwgbGFiZWxzID0gdmFyY29kZV9saXN0KSArCiAgI2dlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IFNhbXBsZUlEKSwgcmVwZWwgPSBUUlVFKSArCiAgbGFicyhlZGdlX3dpZHRoID0gIlNhbXBsZUlEIikgKwogIHRoZW1lX2dyYXBoKCkKCnNhdmVfcGxvdCgidml6L2VjdWFkb3JfTVNjbHVzdGVyc19uZXR3b3JrLnBuZyIsIGVjdWFkb3JfTVNjbHVzdGVyc19uZXR3b3JrLCBiYXNlX3dpZHRoID0gOCwgYmFzZV9oZWlnaHQgPSA2KQplY3VhZG9yX01TY2x1c3RlcnNfbmV0d29yawpgYGAKCiMjIyBEZWZpbmluZyBjbG9uZXMgYnkgTVMKQWxsb3dpbmcgZm9yIDEgYWxsZWxlIGRpZmYKYGBge3J9CmVjdWFkb3JfTVNjbHVzdGVyc19uZXR3b3JrODAgPC0gZWN1TVNfdGlkeSAlPiUgYWN0aXZhdGUoZWRnZXMpICU+JSBmaWx0ZXIoR1Nfc2NvcmUgPj0gMC44MCkgJT4lIAogIGdncmFwaChsYXlvdXQgPSAiZnIiKSArIAogIGdlb21fZWRnZV9saW5rKGNvbG9yID0gImRhcmtncmV5IiwgYWxwaGEgPSAwLjUpICsgCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhmaWxsID0gdmFyY29kZSksIHNoYXBlID0gMjEsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDQpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB2YXJjb2RlX2NvbG9ycyR2YXJjb2RlLCBsYWJlbHMgPSB2YXJjb2RlX2xpc3QpICsKICAjZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gU2FtcGxlSUQpLCByZXBlbCA9IFRSVUUpICsKICBsYWJzKGVkZ2Vfd2lkdGggPSAiU2FtcGxlSUQiKSArCiAgdGhlbWVfZ3JhcGgoKQoKc2F2ZV9wbG90KCJ2aXovZWN1YWRvcl9NU2NsdXN0ZXJzX25ldHdvcmtfUFRTODAucG5nIiwgZWN1YWRvcl9NU2NsdXN0ZXJzX25ldHdvcms4MCwgYmFzZV93aWR0aCA9IDgsIGJhc2VfaGVpZ2h0ID0gNikKZWN1YWRvcl9NU2NsdXN0ZXJzX25ldHdvcms4MApgYGAKCiMjIyBNUyBjbG9uZXMgc3VwcGxlbWVudGFyeSBmaWd1cmUKYGBge3J9CmVjdWFkb3JfTVNjbHVzdGVyc19zdXBwIDwtIGVjdWFkb3JfTVNjbHVzdGVyc19uZXR3b3JrICsgZWN1YWRvcl9NU2NsdXN0ZXJzX25ldHdvcms4MCArCiAgcGxvdF9sYXlvdXQoZ3VpZGVzID0gImNvbGxlY3QiKSArIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gImEiKQogIApzYXZlX3Bsb3QoInZpei9lY3VhZG9yX01TY2x1c3RlcnNfbmV0d29ya3NfYm90aC5wbmciLCBlY3VhZG9yX01TY2x1c3RlcnNfc3VwcCwgYmFzZV93aWR0aCA9IDEyLCBiYXNlX2hlaWdodCA9IDYpCmVjdWFkb3JfTVNjbHVzdGVyc19zdXBwCmBgYAoKIyMjIElkZW50aWZ5aW5nIHJlY29tYmluYW50cyBieSBNUzogdHJhbnNtaXNzaW9uIG5ldHdvcmsKYGBge3J9CmVjdWFkb3JfTVNyZWNvbWJfbmV0d29yayA8LSBlY3VNU190aWR5ICU+JSBhY3RpdmF0ZShlZGdlcykgJT4lIGZpbHRlcihHU19zY29yZSA+PSAwLjUpICU+JSAKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKyAKICBnZW9tX2VkZ2VfbGluayhjb2xvciA9ICJkYXJrZ3JleSIsIGFscGhhID0gMC41KSArIAogIGdlb21fbm9kZV9wb2ludChhZXMoZmlsbCA9IHZhcmNvZGUpLCBzaGFwZSA9IDIxLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSA0LjUpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB2YXJjb2RlX2NvbG9ycyR2YXJjb2RlLCBsYWJlbHMgPSB2YXJjb2RlX2xpc3QpICsKICAjZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gU2FtcGxlSUQpLCByZXBlbCA9IFRSVUUpICsKICBsYWJzKGVkZ2Vfd2lkdGggPSAiU2FtcGxlSUQiKSArCiAgdGhlbWVfZ3JhcGgoKQoKc2F2ZV9wbG90KCJ2aXovZWN1YWRvcl9NU3JlY29tYl9uZXR3b3JrLnBuZyIsIGVjdWFkb3JfTVNyZWNvbWJfbmV0d29yaywgYmFzZV93aWR0aCA9IDgsIGJhc2VfaGVpZ2h0ID0gNikKZWN1YWRvcl9NU3JlY29tYl9uZXR3b3JrCmBgYApUaGlzIHZlcnkgY2xlYXJseSBzaG93cyB0aGF0IGRlc2NyaWJpbmcgdHJhbnNtaXNzaW9uIGR5bmFtaWNzIHVzaW5nIG1pY3Jvc2F0ZWxsaXRlcyBpcyBub3Qgc3VmZmljaWVudCB0byBpZGVudGlmeSByZWNlbnQgZ2VuZXRpYyBleGNoYW5nZXMgYW5kIHJlY2VudCByZWNvbWJpbmF0aW9uL3RyYW5zbWlzc2lvbiBldmVudHMgc2luY2UgZXZlcnl0aGluZyBpcyBjb25uZWN0ZWQgYnkgTVMuIFNpbmNlICp2YXIqIGdlbmVzIGFyZSByYXBpZGx5IGV2b3ZsaW5nIGNvbXBhcmVkIHRvIE1TLCB0aGV5IGFsbG93IHVzIHRvICJ0cmFjayIgcmVjb21iaW5hdGlvbiBhbmQgdHJhbnNtaXNzaW9uIGR5bmFtaWNzIGluIHNwYWNlIGFuZCB0aW1lLiAgCgojIyBDbHVzdGVyaW5nIEFuYWx5c2lzIChoZWF0bWFwcykKIyMjICp2YXIqY29kZSBoZWF0bWFwIGNsdXN0ZXJlZApgYGB7cn0KIyMjVHJ5aW5nIHRvIG9yZGVyIHRoZSBjbHVzdGVycyBieSAieWVhciIKcGhlYXRtYXAodChlY3VfbWF0cml4KSwgY29sID0gYygid2hpdGUiLCAiYmxhY2siKSwKICAgICAgICAgYW5ub3RhdGlvbl9yb3cgPSB2YXJjb2RlX2xpc3QsIAogICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IHZhcmNvZGVfY29sb3JzLCAKICAgICAgICAgZm9udHNpemVfcm93ID0gNSwgZm9udHNpemVfY29sID0gNSwgCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IFQsIGNsdXN0ZXJfY29scyA9IEYsIAogICAgICAgICBsZWdlbmQgPSBGLCAKICAgICAgICAgdHJlZWhlaWdodF9jb2wgPSAwLCAKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEYsCiAgICAgICAgIHNob3dfcm93bmFtZXMgPSBGLCAKICAgICAgICAgI2ZpbGVuYW1lID0gInZpei92YXJjb2RlX2hlYXRtYXAucG5nIiwKICAgICAgICAgd2lkdGggPSA4LCAKICAgICAgICAgaGVpZ2h0ID0gNCkKYGBgCgojIyMgTWljcm9zYXQgaGVhdG1hcApgYGB7cn0KIyMjVHJ5aW5nIHRvIG9yZGVyIHRoZSBjbHVzdGVycyBieSAieWVhciIKcGhlYXRtYXAobWljcm9zYXRfZWN1LCBjb2wgPSBjKCJ3aGl0ZSIsICJibGFjayIpLAogICAgICAgICBhbm5vdGF0aW9uX3JvdyA9IHZhcmNvZGVfbGlzdCwgCiAgICAgICAgIGFubm90YXRpb25fY29sb3JzID0gdmFyY29kZV9jb2xvcnMsIAogICAgICAgICBmb250c2l6ZV9yb3cgPSA1LCBmb250c2l6ZV9jb2wgPSA1LCAKICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVCwgY2x1c3Rlcl9jb2xzID0gRiwgCiAgICAgICAgIGxlZ2VuZCA9IEYsIAogICAgICAgICB0cmVlaGVpZ2h0X2NvbCA9IDAsIAogICAgICAgICBzaG93X2NvbG5hbWVzID0gRiwKICAgICAgICAgc2hvd19yb3duYW1lcyA9IEYsCiAgICAgICAgICNmaWxlbmFtZSA9ICJ2aXovbWljcm9zYXRfaGVhdG1hcC5wbmciLAogICAgICAgICB3aWR0aCA9IDgsIAogICAgICAgICBoZWlnaHQgPSA0KQpgYGAKCiMjIFNwYXRpYWwgQW5hbHlzaXMKIyMjIE1hcCBvZiBFY3VhZG9yCmBgYHtyfQpyZWdpc3Rlcl9nb29nbGUoa2V5ID0gIklOU0VSVF9LRVkiKQoKZ2VvY29kZSgiRWN1YWRvciIpCm1hcCA8LSBnZXRfZ29vZ2xlbWFwKGNlbnRlciA9ICJFY3VhZG9yIiwgem9vbSA9IDcsIG1hcHR5cGUgPSAidGVycmFpbiIsIHN0eWxlID0gImZlYXR1cmU6cG9pLmJ1c2luZXNzfHZpc2liaWxpdHk6b2ZmJnN0eWxlPWZlYXR1cmU6cm9hZHxlbGVtZW50OmxhYmVscy5pY29ufHZpc2liaWxpdHk6b2ZmJnN0eWxlPWZlYXR1cmU6dHJhbnNpdHx2aXNpYmlsaXR5Om9mZiIpIAplY3VfbWFwIDwtIGdnbWFwKG1hcCkgKyB4bGFiKCJMb25naXR1ZGUiKSArIHlsYWIoIkxhdGl0dWRlIikKZWN1X21hcCA8LSBlY3VfbWFwICsgc2NhbGViYXIoeC5taW4gPSAtNzcsIHgubWF4ID0gLTc1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5Lm1pbiA9IC00LjgsIHkubWF4ID0gLTQuNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzdCA9IDEwMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3RfdW5pdCA9ICJrbSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSBULCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwgPSAiV0dTODQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjc3QuYm90dG9tID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3QuZGlzdCA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlaWdodCA9IDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdC5zaXplID0gMykgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX25vcnRoX2Fycm93KGxvY2F0aW9uID0gImJyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFkX3ggPSB1bml0KDAuNCwgImluIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZF95ID0gdW5pdCgwLjQsICJpbiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0eWxlID0gbm9ydGhfYXJyb3dfZmFuY3lfb3JpZW50ZWVyaW5nKSAKCmVjdV9tYXBfem9vbSA8LSBnZ21hcChtYXApICsgeGxhYigiTG9uZ2l0dWRlIikgKyAKICAgICAgICAgIHlsYWIoIkxhdGl0dWRlIikgKyAKICAgICAgICAgIHlsaW0oLTIuMjUsIDEuNCkgKwogICAgICAgICAgc2NhbGViYXIoeC5taW4gPSAtNzcsIHgubWF4ID0gLTc1LAogICAgICAgICAgICAgICAgICAgeS5taW4gPSAtMi4xLCB5Lm1heCA9IC0yLjAsCiAgICAgICAgICAgICAgICAgICBkaXN0ID0gMTAwLCAKICAgICAgICAgICAgICAgICAgIGRpc3RfdW5pdCA9ICJrbSIsIAogICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtID0gVCwgCiAgICAgICAgICAgICAgICAgICBtb2RlbCA9ICJXR1M4NCIsCiAgICAgICAgICAgICAgICAgICAjc3QuYm90dG9tID0gRiwKICAgICAgICAgICAgICAgICAgIHN0LmRpc3QgPSAxLAogICAgICAgICAgICAgICAgICAgaGVpZ2h0ID0gMSwgCiAgICAgICAgICAgICAgICAgICBzdC5zaXplID0gMykgKwogICAgICAgICAgYW5ub3RhdGlvbl9ub3J0aF9hcnJvdyhsb2NhdGlvbiA9ICJiciIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWRfeCA9IHVuaXQoMC45LCAiaW4iKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZF95ID0gdW5pdCgwLjQsICJpbiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHlsZSA9IG5vcnRoX2Fycm93X2ZhbmN5X29yaWVudGVlcmluZykKCmVjdV9tYXBfcGllY2hhcnRzIDwtIGdnbWFwKG1hcCkgKyB4bGFiKCJMb25naXR1ZGUiKSArIAogICAgICAgICAgeWxhYigiTGF0aXR1ZGUiKSArIAogICAgICAgICAgeWxpbSgtMi4yNSwgMS42KSArCiAgICAgICAgICBzY2FsZWJhcih4Lm1pbiA9IC03NywgeC5tYXggPSAtNzUsCiAgICAgICAgICAgICAgICAgICB5Lm1pbiA9IC0yLjEsIHkubWF4ID0gLTIuMCwKICAgICAgICAgICAgICAgICAgIGRpc3QgPSAxMDAsIAogICAgICAgICAgICAgICAgICAgZGlzdF91bml0ID0gImttIiwgCiAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSBULCAKICAgICAgICAgICAgICAgICAgIG1vZGVsID0gIldHUzg0IiwKICAgICAgICAgICAgICAgICAgICNzdC5ib3R0b20gPSBGLAogICAgICAgICAgICAgICAgICAgc3QuZGlzdCA9IDEsCiAgICAgICAgICAgICAgICAgICBoZWlnaHQgPSAxLCAKICAgICAgICAgICAgICAgICAgIHN0LnNpemUgPSAzKSArCiAgICAgICAgICBhbm5vdGF0aW9uX25vcnRoX2Fycm93KGxvY2F0aW9uID0gImJyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZF94ID0gdW5pdCgwLjEsICJpbiIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFkX3kgPSB1bml0KDMuMiwgImluIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0eWxlID0gbm9ydGhfYXJyb3dfZmFuY3lfb3JpZW50ZWVyaW5nKQoKYGBgCgpgYGB7cn0KZWN1YWRvcl9nbWFwX2xvY2F0aW9ucyA8LSBlY3VfbWFwICsgZ2VvbV9wb2ludChkYXRhID0gZWN1X2VwaSwgYWVzKHggPSBsb24sIHkgPSBsYXQsIGZpbGwgPSBMb2NhdGlvbkNvZGUpLCBzaGFwZSA9IDIxLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAzKSArICAgCiAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBsb2NfY29scywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGxvY2F0aW9uTGFiZWxzJExvY2F0aW9uQ29kZSkgKwogIGxhYnMoZmlsbCA9ICJMb2NhdGlvbiIpCgpzYXZlX3Bsb3QoInZpei9lY3VhZG9yX2dvb2dsZW1hcF9zYW1wbGluZ2xvY2F0aW9ucy5wbmciLCBlY3VhZG9yX2dtYXBfbG9jYXRpb25zKQplY3VhZG9yX2dtYXBfbG9jYXRpb25zCmBgYAoKIyMjIE51bWJlciBvZiBpc29sYXRlcyBzYW1wbGVkIHBlciB5ZWFyIHN0cmF0aWZpZWQgYnkgbG9jYXRpb24gLSBiYXIgcGxvdApgYGB7cn0KZWN1X2VwaSA8LSBlY3VfZXBpICU+JSAKICBtdXRhdGUoWWVhciA9IGNhc2Vfd2hlbihEYXRlQ29sbGVjdGVkIDwgIjIwMTMtMTItMzEiIH4iMjAxMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgRGF0ZUNvbGxlY3RlZCA8ICIyMDE0LTEyLTMxIiB+IjIwMTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgIERhdGVDb2xsZWN0ZWQgPCAiMjAxNS0xMi0zMSIgfiIyMDE1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4iQ0hFQ0siKSkgCgpiYXJwbG90X3NhbXBsZXNfcGVybG9jYXRpb24gPC0gZWN1X2VwaSAlPiUgCiAgZ3JvdXBfYnkoTG9jYXRpb25Db2RlLCBZZWFyKSAlPiUgCiAgdGFsbHkoKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IG4sIGZpbGwgPSBMb2NhdGlvbkNvZGUpKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbG9jX2NvbHMsCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBsb2NhdGlvbkxhYmVscyRMb2NhdGlvbkNvZGUpICsKICAgIGJhY2tncm91bmRfZ3JpZChtYWpvciA9ICJ4eSIsIG1pbm9yID0gIm5vbmUiKSArCiAgICBsYWJzKHggPSAiWWVhciIsIAogICAgICAgICB5ID0gIk51bWJlciBvZiBzYW1wbGVzIiwKICAgICAgICAgZmlsbCA9ICJMb2NhdGlvbiIpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgdGhlbWVfY293cGxvdCgpICsgCiAgICBiYWNrZ3JvdW5kX2dyaWQobWFqb3IgPSAieHkiKQoKc2F2ZV9wbG90KCJ2aXovZWN1YWRvcl9iYXJwbG90X3NhbXBsaW5nLnBuZyIsIGJhcnBsb3Rfc2FtcGxlc19wZXJsb2NhdGlvbikKYmFycGxvdF9zYW1wbGVzX3BlcmxvY2F0aW9uIApgYGAKCiMjIyBTYXZlIHNhbXBsaW5nIGxvY2F0aW9ucyBwbG90CmBgYHtyfQpwbG90X3NhbXBsaW5nX2xvY2F0aW9ucyA8LSAoZWN1YWRvcl9nbWFwX2xvY2F0aW9ucyArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpICsgYmFycGxvdF9zYW1wbGVzX3BlcmxvY2F0aW9uICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAnQScpCgpwbG90X3NhbXBsaW5nX2xvY2F0aW9ucwpgYGAKCiMjIyBTcGF0aWFsIG5ldHdvcms6IGdvb2dsZSBtYXAKYGBge3J9CnNlZ19kYXRhIDwtIGVjdV9lZGdlcyAlPiUgZmlsdGVyKEdTX3Njb3JlID49IDAuNSkgCnNlZ19kYXRhIDwtIHNlZ19kYXRhICU+JSBsZWZ0X2pvaW4oZWN1X2VwaSwgYnkgPSBjKCJpZC54Ij0iaWQiKSkKc2VnX2RhdGEgPC0gc2VnX2RhdGEgJT4lIGxlZnRfam9pbihlY3VfZXBpLCBieSA9IGMoImlkLnkiPSJpZCIpKQoKc2VnX2RhdGEgPC0gc2VnX2RhdGEgJT4lIGdyb3VwX2J5KHZhcmNvZGUueCwgdmFyY29kZS55LCBsb24ueCwgbGF0LngsIGxvbi55LCBsYXQueSkgJT4lIHRhbGx5KCkKZWN1X21hcF96b29tICsKICAgICAgICAgIGdlb21fc2VnbWVudChkYXRhID0gc2VnX2RhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBsb24ueCwgeSA9IGxhdC54LCB4ZW5kID0gbG9uLnksIHllbmQgPSBsYXQueSwgYWxwaGEgPSAwLjEsIHNpemUgPSBuKSwKICAgICAgICAgICAgICAgICAgICAgICBsaW5lam9pbiA9ICJtaXRyZSIpICsKICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGVjdV9lcGksIAogICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IGxvbiwgeSA9IGxhdCwgZmlsbCA9IHZhcmNvZGUpLCAKICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMy41LCAKICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIoaCA9IDAuMSwgdyA9IDAuMSkpICsKICAgICAgICAgIHNjYWxlX3NpemVfYXJlYSgpICsKICAgICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHZhcmNvZGVfY29sb3JzJHZhcmNvZGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gdmFyY29kZV9saXN0KSAKYGBgCgojIyMgUmVhbC10aW1lIHNwYXRpYWwgbmV0d29yazogZ29vZ2xlIG1hcApgYGB7cn0Kc2VnX2RhdGExIDwtIGVjdV9lZGdlcyAlPiUgZmlsdGVyKEdTX3Njb3JlID49IDAuNSkgCnNlZ19kYXRhMSA8LSBzZWdfZGF0YTEgJT4lIGxlZnRfam9pbihlY3VfZXBpLCBieSA9IGMoImlkLngiPSJpZCIpKQpzZWdfZGF0YTEgPC0gc2VnX2RhdGExICU+JSBsZWZ0X2pvaW4oZWN1X2VwaSwgYnkgPSBjKCJpZC55Ij0iaWQiKSkKc2VnX2RhdGExIDwtIHNlZ19kYXRhMSAlPiUgcmVuYW1lX2F0KCJEYXRlQ29sbGVjdGVkLngiLCB+IkRhdGVDb2xsZWN0ZWQiKQoKZ29vZ2xlbWFwU2FtcGxlc1JUTmV0IDwtIGVjdV9tYXBfem9vbSArCiAgICAgICAgICBnZW9tX3NlZ21lbnQoZGF0YSA9IHNlZ19kYXRhMSwKICAgICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IGxvbi54LCB5ID0gbGF0LngsIHhlbmQgPSBsb24ueSwgeWVuZCA9IGxhdC55LCBhbHBoYSA9IDAuMSwgc2l6ZSA9IDAuNSksCiAgICAgICAgICAgICAgICAgICAgICAgbGluZWpvaW4gPSAiYmV2ZWwiKSArCiAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBlY3VfZXBpLCAKICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBsb24sIHkgPSBsYXQsIGZpbGwgPSB2YXJjb2RlKSwgCiAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMjEsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDMuNSwgCiAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKGggPSAwLjEsIHcgPSAwLjEpKSArCiAgICAgICAgICBzY2FsZV9zaXplX2FyZWEoKSArCiAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB2YXJjb2RlX2NvbG9ycyR2YXJjb2RlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHZhcmNvZGVfbGlzdCkgKwogICAgICAgICAgc2NhbGVfYWxwaGEoZ3VpZGUgPSAibm9uZSIpICsKICAgICAgICAgIHNjYWxlX3NpemUoZ3VpZGUgPSAibm9uZSIpICsKICAgICAgICAgIHRyYW5zaXRpb25fc3RhdGVzKERhdGVDb2xsZWN0ZWQsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zaXRpb25fbGVuZ3RoID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGVfbGVuZ3RoID0gNSkgKwogICAgICAgICAgbGFicyh0aXRsZSA9ICIiLCAKICAgICAgICAgICAgICAgc3VidGl0bGUgPSAnU2FtcGxlcyBjb2xsZWN0ZWQgb24ge2Nsb3Nlc3Rfc3RhdGV9JykgKwogICAgICAgICAgc2hhZG93X21hcmsoc2l6ZSA9IDMpCgpnb29nbGVtYXBTYW1wbGVzUlROZXRfYW5pbSA8LSBhbmltYXRlKGdvb2dsZW1hcFNhbXBsZXNSVE5ldCwgd2lkdGggPSA4LCBoZWlnaHQgPSA4LCByZXMgPSA1MDAsIHVuaXRzID0gImluIiwgZHVyYXRpb24gPSAxNSwgZnBzID0gMiwgZGV0YWlsID0gNSwgcmVuZGVyID0gZ2lmc2tpX3JlbmRlcmVyKCkpCmFuaW1fc2F2ZSgidml6L3NwYXRpYWxfbmV0d29ya19yZWFsdGltZV9nb29nbGVtYXAuZ2lmIiwgZ29vZ2xlbWFwU2FtcGxlc1JUTmV0X2FuaW0pCgpnb29nbGVtYXBTYW1wbGVzUlROZXRfYW5pbSA8LSBhbmltYXRlKGdvb2dsZW1hcFNhbXBsZXNSVE5ldCwgd2lkdGggPSA4LCBoZWlnaHQgPSA4LCByZXMgPSAyNTAsIHVuaXRzID0gImluIiwgZHVyYXRpb24gPSAxNSwgZnBzID0gMiwgZGV0YWlsID0gNSwgcmVuZGVyID0gZ2lmc2tpX3JlbmRlcmVyKCkpCmFuaW1fc2F2ZSgidml6L3NwYXRpYWxfbmV0d29ya19yZWFsdGltZV9nb29nbGVtYXBfbG93cmVzLmdpZiIsIGdvb2dsZW1hcFNhbXBsZXNSVE5ldF9hbmltKQpgYGAKIVtdKHZpei9zcGF0aWFsX25ldHdvcmtfcmVhbHRpbWVfZ29vZ2xlbWFwX2xvd3Jlcy5naWYpIAoKIyMjICp2YXIqY29kZSBwaWUgY2hhcnRzOgpOb3cgd2Ugd2FudCB0byBvdmVybGFwIHBpZSBjaGFydHMgd2l0aCB0aGUgcHJvcG9ydGlvbiBvZiBpc29sYXRlcyB3aXRoIGVhY2ggKnZhcipjb2RlIGlkZW50aWZpZWQgaW4gYSBnaXZlbiBsb2NhdGlvbiBpbiBlYWNoIHllYXIuIFRoaXMgd2F5IHdlIGNhbiBpbmNsdWRlIGEgbWFwIG9mIHRoZSAqdmFyKmNvZGUgbG9jYXRpb25zIHRoYXQgY2FuIGJlIGluY2x1ZGVkIGluIG91ciBmaWd1cmUgc2hvd2luZyB0aGUgKnZhcipjb2RlIHBlcnNpc3RlbmNlL21haW50ZW5hbmNlIG92ZXIgdGltZS4KYGBge3J9CnZhcmNvZGVfcGllY2hhcnRkYXRhIDwtIGVjdV9lcGkgJT4lIGdyb3VwX2J5KExvY2F0aW9uQ29kZSwgbG9uLCBsYXQsIFllYXIsIHZhcmNvZGUpICU+JSB0YWxseSgpCgpnZ3Bsb3QodmFyY29kZV9waWVjaGFydGRhdGEsIGFlcyh4ID0gIiIsIHkgPSBuLCBmaWxsID0gdmFyY29kZSkpICsKICBnZW9tX2Jhcih3aWR0aCA9IDEsIHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJmaWxsIikgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB2YXJjb2RlX2NvbG9ycyR2YXJjb2RlLCAKICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSB2YXJjb2RlX2xpc3QpICsKICBmYWNldF93cmFwKH5Mb2NhdGlvbkNvZGUpICsgCiAgY29vcmRfcG9sYXIodGhldGEgPSAieSIsIHN0YXJ0ID0gMCkgKwogIHRoZW1lX3ZvaWQoKQoKZ2dwbG90KHZhcmNvZGVfcGllY2hhcnRkYXRhLCBhZXMoeCA9ICIiLCB5ID0gbiwgZmlsbCA9IHZhcmNvZGUpKSArCiAgZ2VvbV9iYXIod2lkdGggPSAxLCBzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZmlsbCIpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gdmFyY29kZV9jb2xvcnMkdmFyY29kZSwgCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gdmFyY29kZV9saXN0KSArCiAgZmFjZXRfd3JhcChZZWFyfkxvY2F0aW9uQ29kZSkgKyAKICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5Iiwgc3RhcnQgPSAwKSArCiAgdGhlbWVfdm9pZCgpCmBgYAoKIyMjIFBpZSBjaGFydCBtYXBzIGJ5IHllYXIKRmlyc3Qgd2UgbmVlZCB0byBjcmVhdGUgYSBkYXRhZnJhbWUgd2l0aCAlIHZhcmNvZGUgaW4gZWFjaCBsb2NhdGlvbi4KYGBge3J9CmRmX2xvY2F0aW9uX3ZhcmNvZGVfdG90YWxzIDwtIGVjdV9lcGkgJT4lIAogICAgICAgIHRhYnlsKExvY2F0aW9uQ29kZSwgWWVhcikgJT4lIHJlbmFtZV9hdCgiMjAxMyIsIH4idG90YWxfMjAxMyIpICU+JSByZW5hbWVfYXQoIjIwMTQiLCB+InRvdGFsXzIwMTQiKSAlPiUgcmVuYW1lX2F0KCIyMDE1IiwgfiJ0b3RhbF8yMDE1IikgCgp2YXJjb2Rlc19ieV9sb2MgPC0gZWN1X2VwaSAlPiUgdGFieWwoTG9jYXRpb25Db2RlLCB2YXJjb2RlLCBZZWFyKQoKdmFyY29kZV9wcm9wXzIwMTMgPC0gdmFyY29kZXNfYnlfbG9jW1sxXV0gJT4lIAogICAgICAgIGFkb3JuX3RvdGFscygiY29sIikgJT4lIAogICAgICAgIG11dGF0ZSh5ZWFyID0gIjIwMTMiKSAKCnZhcmNvZGVfcHJvcF8yMDE0IDwtIHZhcmNvZGVzX2J5X2xvY1tbMl1dICU+JSAKICAgICAgICBhZG9ybl90b3RhbHMoImNvbCIpICU+JSAKICAgICAgICBtdXRhdGUoeWVhciA9ICIyMDE0IikgCgp2YXJjb2RlX3Byb3BfMjAxNSA8LSB2YXJjb2Rlc19ieV9sb2NbWzNdXSAlPiUgCiAgICAgICAgYWRvcm5fdG90YWxzKCJjb2wiKSAlPiUgCiAgICAgICAgbXV0YXRlKHllYXIgPSAiMjAxNSIpIAogICAgICAgIAoKCmxvY2F0aW9uX2Nvb3JkcyA8LSBlY3VfZXBpICU+JSBncm91cF9ieShMb2NhdGlvbkNvZGUsIGxvbiwgbGF0KSAlPiUgdGFsbHkoKSAlPiUgc2VsZWN0KC1uKQoKdmFyY29kZV9wcm9wcyA8LSByYmluZCh2YXJjb2RlX3Byb3BfMjAxMywgdmFyY29kZV9wcm9wXzIwMTQsIHZhcmNvZGVfcHJvcF8yMDE1KQp2YXJjb2RlX3Byb3BzIDwtIHZhcmNvZGVfcHJvcHMgJT4lIGxlZnRfam9pbihsb2NhdGlvbl9jb29yZHMsIGJ5ID0gIkxvY2F0aW9uQ29kZSIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoTG9jYXRpb25Db2RlLCBsb24sIGxhdCwgeWVhciwgVG90YWwsIHZhcmNvZGUxOnZhcmNvZGU5KSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHJhZGl1cyA9ICgwLjQgKiBzcXJ0KFRvdGFsKSAvIHNxcnQobWF4KFRvdGFsKSkpKSAKYGBgCgojIyMjICp2YXIqY29kZSBzcGF0aWFsIGRpc3RyaWJ1dGlvbjogMjAxMwpgYGB7cn0KcGllY2hhcnRzXzIwMTMgPC0gdmFyY29kZV9wcm9wcyAlPiUgZmlsdGVyKHllYXIgPT0gIjIwMTMiLCBUb3RhbCA+IDApCgptYXBfcGllc18yMDEzIDwtIGVjdV9tYXBfcGllY2hhcnRzICsKICBnZW9tX3NjYXR0ZXJwaWUoZGF0YSA9IHBpZWNoYXJ0c18yMDEzLCAKICAgICAgICAgICAgICAgICAgYWVzKHggPSBsb24sIAogICAgICAgICAgICAgICAgICAgICAgeSA9IGxhdCwgCiAgICAgICAgICAgICAgICAgICAgICByID0gcmFkaXVzLAogICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBMb2NhdGlvbkNvZGUpLAogICAgICAgICAgICAgICAgICBjb2xzID0gYygidmFyY29kZTEiLCAidmFyY29kZTIiLCAidmFyY29kZTMiLCAidmFyY29kZTQiLCAidmFyY29kZTUiLCAidmFyY29kZTYiLCAidmFyY29kZTciLCAidmFyY29kZTgiLCAidmFyY29kZTkiKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKGJyZWFrcyA9IHZhcmNvZGVfbGlzdCwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSB2YXJjb2RlX2NvbG9ycyR2YXJjb2RlLCAKICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSB2YXJjb2RlX2xpc3QpICsKICBnZW9tX3NjYXR0ZXJwaWVfbGVnZW5kKHBpZWNoYXJ0c18yMDEzJHJhZGl1cywgCiAgICAgICAgICAgICAgICAgICAgICAgICBuID0gMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbGxlciA9IGZ1bmN0aW9uKHgpIHggPSB1bmlxdWUocGllY2hhcnRzXzIwMTMkVG90YWwpLAogICAgICAgICAgICAgICAgICAgICAgICAgeCA9IC03NS42LCAKICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSAtMS41KSAKCnNhdmVfcGxvdCgidml6L2VjdWFkb3JfZ29vZ2xlbWFwX3BpZWNoYXJ0czIwMTMucG5nIiwgbWFwX3BpZXNfMjAxMywgYmFzZV93aWR0aCA9IDgsIGJhc2VfaGVpZ2h0ID0gNikKbWFwX3BpZXNfMjAxMwpgYGAKCiMjIyMgKnZhcipjb2RlIHNwYXRpYWwgZGlzdHJpYnV0aW9uOiAyMDE0CmBgYHtyfQpwaWVjaGFydHNfMjAxNCA8LSB2YXJjb2RlX3Byb3BzICU+JSBmaWx0ZXIoeWVhciA9PSAiMjAxNCIsIFRvdGFsID4gMCkKCm1hcF9waWVzXzIwMTQgPC0gZWN1X21hcF9waWVjaGFydHMgKwogIGdlb21fc2NhdHRlcnBpZShkYXRhID0gcGllY2hhcnRzXzIwMTQsIAogICAgICAgICAgICAgICAgICBhZXMoeCA9IGxvbiwgCiAgICAgICAgICAgICAgICAgICAgICB5ID0gbGF0LCAKICAgICAgICAgICAgICAgICAgICAgIHIgPSByYWRpdXMsCiAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IExvY2F0aW9uQ29kZSksCiAgICAgICAgICAgICAgICAgIGNvbHMgPSBjKCJ2YXJjb2RlMSIsICJ2YXJjb2RlMiIsICJ2YXJjb2RlMyIsICJ2YXJjb2RlNCIsICJ2YXJjb2RlNSIsICJ2YXJjb2RlNiIsICJ2YXJjb2RlNyIsICJ2YXJjb2RlOCIsICJ2YXJjb2RlOSIpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwoYnJlYWtzID0gdmFyY29kZV9saXN0LAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IHZhcmNvZGVfY29sb3JzJHZhcmNvZGUsIAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHZhcmNvZGVfbGlzdCkgKwogIGdlb21fc2NhdHRlcnBpZV9sZWdlbmQocGllY2hhcnRzXzIwMTQkcmFkaXVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG4gPSAzLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsbGVyID0gZnVuY3Rpb24oeCkgeCA9IHVuaXF1ZShwaWVjaGFydHNfMjAxNCRUb3RhbCksCiAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gLTc1LjQsIAogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IC0xLjYpIAoKc2F2ZV9wbG90KCJ2aXovZWN1YWRvcl9nb29nbGVtYXBfcGllY2hhcnRzMjAxNC5wbmciLCBtYXBfcGllc18yMDE0LCBiYXNlX3dpZHRoID0gOCwgYmFzZV9oZWlnaHQgPSA2KQptYXBfcGllc18yMDE0CmBgYAoKIyMjIyAqdmFyKmNvZGUgc3BhdGlhbCBkaXN0cmlidXRpb246IDIwMTQKYGBge3J9CnBpZWNoYXJ0c18yMDE1IDwtIHZhcmNvZGVfcHJvcHMgJT4lIGZpbHRlcih5ZWFyID09ICIyMDE1IiwgVG90YWwgPiAwKQoKbWFwX3BpZXNfMjAxNSA8LSBlY3VfbWFwX3BpZWNoYXJ0cyArCiAgZ2VvbV9zY2F0dGVycGllKGRhdGEgPSBwaWVjaGFydHNfMjAxNSwgCiAgICAgICAgICAgICAgICAgIGFlcyh4ID0gbG9uLCAKICAgICAgICAgICAgICAgICAgICAgIHkgPSBsYXQsIAogICAgICAgICAgICAgICAgICAgICAgciA9IHJhZGl1cywKICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gTG9jYXRpb25Db2RlKSwKICAgICAgICAgICAgICAgICAgY29scyA9IGMoInZhcmNvZGUxIiwgInZhcmNvZGUyIiwgInZhcmNvZGUzIiwgInZhcmNvZGU0IiwgInZhcmNvZGU1IiwgInZhcmNvZGU2IiwgInZhcmNvZGU3IiwgInZhcmNvZGU4IiwgInZhcmNvZGU5IikpICsKICBzY2FsZV9maWxsX21hbnVhbChicmVha3MgPSB2YXJjb2RlX2xpc3QsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gdmFyY29kZV9jb2xvcnMkdmFyY29kZSwgCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gdmFyY29kZV9saXN0KSArCiAgZ2VvbV9zY2F0dGVycGllX2xlZ2VuZChwaWVjaGFydHNfMjAxNSRyYWRpdXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgbiA9IDMsIAogICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxsZXIgPSBmdW5jdGlvbih4KSB4ID0gdW5pcXVlKHBpZWNoYXJ0c18yMDE1JFRvdGFsKSwKICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAtNzUuNCwgCiAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gLTEuNikgCgpzYXZlX3Bsb3QoInZpei9lY3VhZG9yX2dvb2dsZW1hcF9waWVjaGFydHMyMDE1LnBuZyIsIG1hcF9waWVzXzIwMTUsIGJhc2Vfd2lkdGggPSA4LCBiYXNlX2hlaWdodCA9IDYpCm1hcF9waWVzXzIwMTUKYGBgCgojIyMjIExlYWZsZXQganVzdCB0byB2aXN1YWxpemUKYGBge3J9CmxpYnJhcnkobGVhZmxldC5taW5pY2hhcnRzKQpsaWJyYXJ5KGxlYWZsZXQpCgpkYXRhX2xlYWYgPC0gdmFyY29kZV9wcm9wcyAlPiUgCiAgc2VsZWN0KExvY2F0aW9uQ29kZSwgbG9uLCBsYXQsIHllYXIsIFRvdGFsLCBzdGFydHNfd2l0aCgidmFyY29kZSIpKSAlPiUgCiAgbXV0YXRlX2F0KHZhcnMoLW9uZV9vZigiTG9jYXRpb25Db2RlIiwgImxhdCIsICJsb24iLCAieWVhciIpKSwgYXMubnVtZXJpYykKCmxlYWZsZXQoZGF0YV9sZWFmKSAlPiUgCiAgICAgICAgICAgIGFkZFRpbGVzKCkgJT4lIAogICAgICAgICAgICBhZGRNaW5pY2hhcnRzKGxuZyA9IGRhdGFfbGVhZiRsb24sIGxhdCA9IGRhdGFfbGVhZiRsYXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJwaWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWUgPSBkYXRhX2xlYWYkeWVhciwKICAgICAgICAgICAgICAgICAgICAgICAgICBjaGFydGRhdGEgPSBkYXRhX2xlYWZbLCBjKCJ2YXJjb2RlMSIsICJ2YXJjb2RlMiIsICJ2YXJjb2RlMyIsICJ2YXJjb2RlNCIsICJ2YXJjb2RlNSIsICJ2YXJjb2RlNiIsICJ2YXJjb2RlNyIsICJ2YXJjb2RlOCIsICJ2YXJjb2RlOSIpXSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvclBhbGV0dGUgPSBjKCIjZmI5YTk5IiwgIiNlNTM4YTkiLCAiIzQ4QjI0RiIsICIjMzBkNWM4IiwgIiNFNEIwMzEiLCAiIzMwOTBkNSIsICIjQ0FEOTNGIiwgIiM5YWM0YjMiLCAiI2E4ODBiYiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoID0gNTAgKiBzcXJ0KGRhdGFfbGVhZiRUb3RhbCkgLyBzcXJ0KG1heChkYXRhX2xlYWYkVG90YWwpKSwgdHJhbnNpdGlvblRpbWUgPSAwKSAlPiUgCiAgICAgICAgICAgIGFkZEVhc3lCdXR0b24oZWFzeUJ1dHRvbigKICAgICAgICAgICAgICAgIGljb24gPSAiZmEtY3Jvc3NoYWlycyIsIHRpdGxlID0gIk1FIiwKICAgICAgICAgICAgICAgIG9uQ2xpY2sgPSBKUygiZnVuY3Rpb24oYnRuLCBtYXApeyBtYXAubG9jYXRlKHtzZXRWaWV3OiB0cnVlfSk7IH0iKSkpICU+JSAKICAgICAgICAgICAgYWRkU2NhbGVCYXIocG9zaXRpb24gPSAiYm90dG9tbGVmdCIsIG9wdGlvbnMgPSBzY2FsZUJhck9wdGlvbnMobWV0cmljID0gVFJVRSwgaW1wZXJpYWwgPSBGKSkKYGBgCgojIyMgU3BhdGlhbCAqdmFyKmNvZGUgbmV0d29yawpgYGB7cn0KZGF0YV9waWVjaGFydG5ldHdvcmsgPC0gZWN1X2VwaSAlPiUKICAgICAgICB0YWJ5bChMb2NhdGlvbkNvZGUsIHZhcmNvZGUpICU+JSAKICAgICAgICBhZG9ybl90b3RhbHMoImNvbCIpICU+JSAKICAgICAgICBtdXRhdGUocmFkaXVzID0gKDAuMyAqIHNxcnQoVG90YWwpIC8gc3FydChtYXgoVG90YWwpKSkpICU+JSBsZWZ0X2pvaW4obG9jYXRpb25fY29vcmRzLCBieSA9ICJMb2NhdGlvbkNvZGUiKQoKbWFwX3BpZXNfbmV0d29yayA8LSBnZ21hcChtYXApICsgeGxhYigiTG9uZ2l0dWRlIikgKyAKICAgICAgICAgIHlsYWIoIkxhdGl0dWRlIikgKyAKICAgICAgICAgIHlsaW0oLTIuMiwgMS42KSArCiAgICAgICAgICBzY2FsZWJhcih4Lm1pbiA9IC03NywgeC5tYXggPSAtNzUsCiAgICAgICAgICAgICAgICAgICB5Lm1pbiA9IC0yLjEsIHkubWF4ID0gLTIuMCwKICAgICAgICAgICAgICAgICAgIGRpc3QgPSAxMDAsIAogICAgICAgICAgICAgICAgICAgZGlzdF91bml0ID0gImttIiwgCiAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0gPSBULCAKICAgICAgICAgICAgICAgICAgIG1vZGVsID0gIldHUzg0IiwKICAgICAgICAgICAgICAgICAgICNzdC5ib3R0b20gPSBGLAogICAgICAgICAgICAgICAgICAgc3QuZGlzdCA9IDEsCiAgICAgICAgICAgICAgICAgICBoZWlnaHQgPSAxLCAKICAgICAgICAgICAgICAgICAgIHN0LnNpemUgPSAzKSArCiAgICAgICAgICBhbm5vdGF0aW9uX25vcnRoX2Fycm93KGxvY2F0aW9uID0gImJyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhZF94ID0gdW5pdCgwLjEsICJpbiIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFkX3kgPSB1bml0KDMuMiwgImluIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0eWxlID0gbm9ydGhfYXJyb3dfZmFuY3lfb3JpZW50ZWVyaW5nKSArCiAgICAgICAgICBnZW9tX3NlZ21lbnQoZGF0YSA9IHNlZ19kYXRhLAogICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gbG9uLngsIHkgPSBsYXQueCwgeGVuZCA9IGxvbi55LCB5ZW5kID0gbGF0LnksIGFscGhhID0gMC4xLCBzaXplID0gbiksCiAgICAgICAgICAgICAgICAgICAgICAgbGluZWpvaW4gPSAibWl0cmUiKSArCiAgZ2VvbV9zY2F0dGVycGllKGRhdGEgPSBkYXRhX3BpZWNoYXJ0bmV0d29yaywgCiAgICAgICAgICAgICAgICAgIGFlcyh4ID0gbG9uLCAKICAgICAgICAgICAgICAgICAgICAgIHkgPSBsYXQsIAogICAgICAgICAgICAgICAgICAgICAgciA9IHJhZGl1cywKICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gTG9jYXRpb25Db2RlKSwKICAgICAgICAgICAgICAgICAgY29scyA9IGMoInZhcmNvZGUxIiwgInZhcmNvZGUyIiwgInZhcmNvZGUzIiwgInZhcmNvZGU0IiwgInZhcmNvZGU1IiwgInZhcmNvZGU2IiwgInZhcmNvZGU3IiwgInZhcmNvZGU4IiwgInZhcmNvZGU5IikpICsKICBzY2FsZV9maWxsX21hbnVhbChicmVha3MgPSB2YXJjb2RlX2xpc3QsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gdmFyY29kZV9jb2xvcnMkdmFyY29kZSwgCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gdmFyY29kZV9saXN0KSArCiAgc2NhbGVfYWxwaGEoZ3VpZGUgPSAibm9uZSIpICsKICBzY2FsZV9zaXplKGd1aWRlID0gIm5vbmUiKSArCiAgZ2VvbV9zY2F0dGVycGllX2xlZ2VuZChkYXRhX3BpZWNoYXJ0bmV0d29yayRyYWRpdXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgbiA9IDUsIAogICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxsZXIgPSBmdW5jdGlvbih4KSB4ID0gc29ydCh1bmlxdWUoZGF0YV9waWVjaGFydG5ldHdvcmskVG90YWwpKSwKICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAtNzUuNCwgCiAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gLTEuNikgCgpzYXZlX3Bsb3QoInZpei9lY3VhZG9yX2dvb2dsZW1hcF9zcGF0aWFsbmV0d29yay5wbmciLCBtYXBfcGllc19uZXR3b3JrLCBiYXNlX3dpZHRoID0gOCwgYmFzZV9oZWlnaHQgPSA2KQptYXBfcGllc19uZXR3b3JrCmBgYAoKIyMgU291dGggQW1lcmljYQojIyMgTU9JIGluIFNvdXRoIEFtZXJpY2EKYGBge3J9CmRhdGFfTU9JIDwtIGRhdGEuZnJhbWUoY29sU3VtcyhtYXRyaXhfYWxsKSkKY29sbmFtZXMoZGF0YV9NT0kpIDwtIGMoInJlcGVydG9pcmVfc2l6ZSIpCmRhdGFfTU9JIDwtIGRhdGFfTU9JICU+JSByb3duYW1lc190b19jb2x1bW4oIlNhbXBsZUlEIikKCmRhdGFfTU9JJExvY2F0aW9uIDwtIGlmZWxzZShncmVwbCgiXkciLCBkYXRhX01PSSRTYW1wbGVJRCwgaWdub3JlLmNhc2UgPSBUKSwgIkZyZW5jaCBHdWlhbmEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJeUCIsIGRhdGFfTU9JJFNhbXBsZUlELCBpZ25vcmUuY2FzZSA9IFQpLCAiUGVydSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJeViIsIGRhdGFfTU9JJFNhbXBsZUlELCBpZ25vcmUuY2FzZSA9IFQpLCAiVmVuZXp1ZWxhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJeQ29sIiwgZGF0YV9NT0kkU2FtcGxlSUQsIGlnbm9yZS5jYXNlID0gVCksICJDb2xvbWJpYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgiXkVDUGYiLCBkYXRhX01PSSRTYW1wbGVJRCwgaWdub3JlLmNhc2UgPSBUKSwgIkVjdWFkb3IiLCAiQ0hFQ0siKSkpKSkKZGF0YV9NT0kkTG9jYXRpb24gPC0gYXMuZmFjdG9yKGRhdGFfTU9JJExvY2F0aW9uKQpsZXZlbHMoZGF0YV9NT0kkTG9jYXRpb24pCmBgYCAKCiMjIyMgV2hhdCBhcmUgdGhlIHN1bW1hcnkgc3RhdGlzdGljcyBmb3IgTU9JPwpgYGB7cn0Ka2FibGUoZGF0YV9NT0kgJT4lIGdyb3VwX2J5KExvY2F0aW9uKSAlPiUgc3VtbWFyaXplKG1pbiA9IG1pbihyZXBlcnRvaXJlX3NpemUpLCBtZWQgPSBtZWRpYW4ocmVwZXJ0b2lyZV9zaXplKSwgbWVhbiA9IG1lYW4ocmVwZXJ0b2lyZV9zaXplKSwgbWF4ID0gbWF4KHJlcGVydG9pcmVfc2l6ZSkpKSAlPiUga2FibGVfc3R5bGluZygpCmBgYAoKU2V0IHRoZSBjb2xvciBzY2FsZSBmb3IgZWFjaCBjb3VudHJ5CmBgYHtyfQpjb3VudHJ5X2xpc3QgPC0gZGF0YV9NT0kgJT4lIHNlbGVjdChTYW1wbGVJRCwgTG9jYXRpb24pCmNvdW50cnlfbGlzdCRTYW1wbGVJRCA8LSBhcy5mYWN0b3IoY291bnRyeV9saXN0JFNhbXBsZUlEKQpjb3VudHJ5X2xpc3QkTG9jYXRpb24gPC0gYXMuZmFjdG9yKGNvdW50cnlfbGlzdCRMb2NhdGlvbikKY291bnRyeV9saXN0IDwtIGNvdW50cnlfbGlzdCAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJTYW1wbGVJRCIpCgpjb3VudHJ5X2NvbG9ycyA8LSBsaXN0KExvY2F0aW9uID0gYygiQ29sb21iaWEiID0gIiNmZGI0NjIiLCAiRWN1YWRvciIgPSAiI2ZiODA3MiIsICJGcmVuY2ggR3VpYW5hIiA9ICIjYTZkODU0IiwgIlBlcnUiID0gIiM2NmMyYTUiLCAiVmVuZXp1ZWxhIiA9ICIjYmViYWRhIikpCmBgYAoKCiMjIyMgV2hhdCBhcmUgdGhlIE1PSSBwYXR0ZXJucyBpbiBTb3V0aCBBbWVyaWNhbiAqUC4gZmFsY2lwYXJ1bSogaXNvbGF0ZXM/CmBgYHtyfQpwbG90X01PSV9TQW0gPC0gZ2dwbG90KGRhdGEgPSBkYXRhX01PSSwgYWVzKHggPSBmYWN0b3IoU2FtcGxlSUQpLCBmaWxsID0gTG9jYXRpb24pKSArIAogIGdlb21fYmFyKGFlcyh5ID0gcmVwZXJ0b2lyZV9zaXplKSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb3VudHJ5X2NvbG9ycyRMb2NhdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjb3VudHJ5X2xpc3QpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEwMCwgYnkgPSAzMCkpICsgCiAgbGFicyh4ID0gIklzb2xhdGUiLAogICAgICAgeSA9ICJSZXBlcnRvaXJlIHNpemUiLAogICAgICAgZmlsbCA9ICIiKSArCiAgdGhlbWVfY293cGxvdCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCkpICsgI2VsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSkpICsKICBiYWNrZ3JvdW5kX2dyaWQobWFqb3IgPSAieSIsIG1pbm9yID0gIm5vbmUiKQoKc2F2ZV9wbG90KCJ2aXovU0FtX01PSS5wbmciLCBwbG90X01PSV9TQW0pCnBsb3RfTU9JX1NBbQpgYGAKCiMjIE51bWJlciBvZiBzaGFyZWQgdHlwZXMgYnkgY291bnRyeTogU291dGggQW1lcmljYQpDcmVhdGUgYSBwcmVzZW5jZS9hYnNlbmNlIG1hdHJpeCBqdXN0IG9mIGVhY2ggY291bnRyeSBhcyBhIHBvcHVsYXRpb24gKG5vdCBpc29sYXRlIGJ5IGlzb2xhdGUpCmBgYHtyfQpjb3VudHJ5X21hdHJpeCA8LSBtYXRyaXhfYWxsICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigiREJMYV90eXBlIikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoQ29sb21iaWEgPSByb3dTdW1zKC5bZ3JlcGwoIl5Db2wiLCBjb2xuYW1lcyguKSldLCBuYS5ybSA9IFQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRWN1YWRvciA9IHJvd1N1bXMoLltncmVwbCgiXkVDUGYiLCBjb2xuYW1lcyguKSldLCBuYS5ybSA9IFQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYEZyZW5jaCBHdWlhbmFgID0gcm93U3VtcyguW2dyZXBsKCJeRyIsIGNvbG5hbWVzKC4pKV0sIG5hLnJtID0gVCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQZXJ1ID0gcm93U3VtcyguW2dyZXBsKCJeUCIsIGNvbG5hbWVzKC4pKV0sIG5hLnJtID0gVCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWZW5lenVlbGEgPSByb3dTdW1zKC5bZ3JlcGwoIl5WIiwgY29sbmFtZXMoLikpXSwgbmEucm0gPSBUKSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoREJMYV90eXBlLCBDb2xvbWJpYTpWZW5lenVlbGEpCgpjb3VudHJ5X21hdHJpeCA8LSBjb3VudHJ5X21hdHJpeCAlPiUgbXV0YXRlKENvbG9tYmlhID0gaWZlbHNlKENvbG9tYmlhID4gMCwgMSwgMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRWN1YWRvciA9IGlmZWxzZShFY3VhZG9yID4gMCwgMSwgMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYEZyZW5jaCBHdWlhbmFgID0gaWZlbHNlKGBGcmVuY2ggR3VpYW5hYCA+IDAsIDEsIDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBlcnUgPSBpZmVsc2UoUGVydSA+IDAsIDEsIDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFZlbmV6dWVsYSA9IGlmZWxzZShWZW5lenVlbGEgPiAwLCAxLCAwKSkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uX3RvX3Jvd25hbWVzKCJEQkxhX3R5cGUiKQojd3JpdGUuY3N2KGNvdW50cnlfbWF0cml4LCAiZGF0YS9jb3VudHJ5X2JpbmFyeS5jc3YiKQpgYGAKVGhlIG51bWJlciBvZiBzaGFyZWQgdHlwZXMgaWRlbnRpZmllZCBpbiB0aGUgY291bnRyaWVzIHdhcyBhcyBmb2xsb3dzOgpgciBrYWJsZShjb3VudHJ5X21hdHJpeCAlPiUgbXV0YXRlKHNoYXJlZCA9IHJvd1N1bXMoLikpICU+JSBncm91cF9ieShzaGFyZWQpICU+JSBjb3VudCgpKSAlPiUga2FibGVfc3R5bGluZygpYC4gIAoKIyMgQ2x1c3RlcmVkIEhlYXRtYXAgU291dGggQW1lcmljYSAKV2UgY2FuIGFsc28gcGxvdCB0aGlzIGFzIGEgaGVhdG1hcCwgd2hpY2ggY2x1c3RlcnMgdGhlIGNvdW50cmllcyBieSB0aGUgbnVtYmVyIG9mIHR5cGVzIHRoZXkgc2hhcmUuIFRoZXJlZm9yZSwgY291bnRyaWVzIHRoYXQgc2hhcmUgbW9yZSB0eXBlcyB3aWxsIGJlIGNsdXN0ZXJlZCB0b2dldGhlci4gCmBgYHtyfQpDb3VudHJ5IDwtIGMoIkNvbG9tYmlhIChOPTExMikiLCAiRWN1YWRvciAoTj0xOTUpIiwgIkZyZW5jaCBHdWlhbmEgKE49MjQ5KSIsICJQZXJ1IChOPTE1NykiLCAiVmVuZXp1ZWxhIChOPTE3NikiKQpsb2NhdGlvbiA8LSBjKCJDb2xvbWJpYSAoTj0xMTIpIiwgIkVjdWFkb3IgKE49MTk1KSIsICJGcmVuY2ggR3VpYW5hIChOPTI0OSkiLCAiUGVydSAoTj0xNTcpIiwgIlZlbmV6dWVsYSAoTj0xNzYpIikKYW5ub19jb2xzIDwtIGRhdGEuZnJhbWUobG9jYXRpb24sIENvdW50cnkpCmFubm9fY29scyA8LSBhbm5vX2NvbHMgJT4lIGNvbHVtbl90b19yb3duYW1lcygibG9jYXRpb24iKQpjb2xvcnNfYW5ubyA8LSBsaXN0KENvdW50cnkgPSBjKGBDb2xvbWJpYSAoTj0xMTIpYCA9ICIjZmRiNDYyIiwgYEVjdWFkb3IgKE49MTk1KWAgPSAiIzY2YzJhNSIsIGBGcmVuY2ggR3VpYW5hIChOPTI0OSlgID0gIiNhNmQ4NTQiLCBgUGVydSAoTj0xNTcpYCA9ICIjZmI4MDcyIiwgYFZlbmV6dWVsYSAoTj0xNzYpYCA9ICIjYmViYWRhIikpCgpjb3VudHJ5X2hlYXRtYXAgPC0gcGhlYXRtYXAodChjb3VudHJ5X21hdHJpeCksIGNvbCA9IGMoIndoaXRlIiwgImJsYWNrIiksIGFubm90YXRpb25fcm93ID0gYW5ub19jb2xzLCBhbm5vdGF0aW9uX2NvbG9ycyA9IGNvbG9yc19hbm5vLCBmb250c2l6ZV9yb3cgPSA1LCBmb250c2l6ZV9jb2wgPSA1LCBzaG93X2NvbG5hbWVzID0gRiwgc2hvd19yb3duYW1lcyA9IEYsIGxlZ2VuZCA9IEYsIHRyZWVoZWlnaHRfY29sID0gMCkKCnNhdmVfcGxvdCgidml6L1NBbV9jb3VudHJ5X2hlYXRtYXAucG5nIiwgY291bnRyeV9oZWF0bWFwLCBiYXNlX3dpZHRoID0gOCwgYmFzZV9oZWlnaHQgPSA0KQpjb3VudHJ5X2hlYXRtYXAKYGBgCgojIyBHZW5ldGljIFNpbWlsYXJpdHkgYW5kIE5ldHdvcmsgQW5hbHlzaXM6IFNvdXRoIEFtZXJpY2EKRm9yIHRoZSBkaXJlY3Rpb25hbCBQVFMgYW1vbmcgU291dGggQW1lcmljYW4gaXNvbGF0ZXMsIHdlIGNvbnNpZGVyIGJvdGggdGhlICJmb3J3YXJkIiBhbmQgInJldmVyc2UiIGRpcmVjdGlvbiBzaW5jZSB0aGVyZSBpcyBub3QgcmVhbCB0ZW1wb3JhbCBhc3BlY3QgdG8gdGhpcyBkYXRhc2V0LiBUaGUgc2FtcGxpbmcgbG9jYXRpb25zIGFuZCBzYW1wbGluZyB0aW1lcyBkaWZmZXIgZ3JlYXRseSwgc28gd2UgYXJlIG9ubHkgaW50ZXJlc3RlZCBpbiBpZGVudGlmeWluZyBjbHVzdGVyIG9mIGdlbmV0aWNhbGx5LXJlbGF0ZWQgcGFyYXNpdGVzIGluIHNwYWNlIGFuZC9vciB0aW1lIChpLmUuIG5vdCByZWNlbnQgdHJhbnNtaXNzaW9uIGV2ZW50cyBvciAicmVhbC10aW1lIiByZWNvbWJpbmF0aW9ucykuIApgYGB7ciBTQW0gZ2VuZXRpYyBzaW1pbGFyaXR5fQpnZW5TaW1fYWxsIDwtIGdlbmV0aWNTaW1pbGFyaXR5KHQobWF0cml4X2FsbCkpCkdTdGFibGVfYWxsIDwtIEdTbWF0cml4VG9UYWJsZShnZW5TaW1fYWxsKSAKYGBgCgpIZXJlIHdlIGRvIG5vdCBuZWVkIHRvIHNlbGVjdCBvbmx5IHRoZSAiYmFja3dhcmRzIGluIHRpbWUiIGRpcmVjdGlvbiwgYmVjYXVzZSB0aGUgdGltZXMgYmV0d2VlbiBzYW1wbGluZyBjb2xsZWN0aW9ucyB2YXJ5IGdyZWF0bHkuIFdlIGFyZSBvbmx5IGludGVyZXN0ZWQgaW4gaWRlbnRpZnlpbmcgZ2VuZXRpY2FsbHktcmVsYXRlZCBwYXJhc2l0ZXMgaW4gc3BhY2UgYW5kIHRpbWUgKGkuZS4gbm90IGVwaWRlbWlvbG9naWNhbCB0aW1lIGJ1dCBwZXJoYXBzIGV2b2x1dGlvbmFyeSB0aW1lKS4gQmVjYXVzZSB3ZSBkb24ndCBrbm93IGlmIHRoZSBvcmRlciBtYXR0ZXJzIChpLmUuIGRpZmZlcmVudCBjb3VudHJpZXMpIHdlIGNhbiB1c2UgYm90aCBkaXJlY3Rpb25zLgoKQ3JlYXRlIGFuIGVwaSBkYXRhc2V0IGZvciBTb3V0aCBBbWVyaWNhLgpgYGB7cn0KYWxsX2VwaSA8LSBkYXRhX01PSSAlPiUgbXV0YXRlKGlkID0gMTpucm93KC4pKQpgYGAKCmBgYHtyfQpHU2FsbF9lZGdlcyA8LSBHU3RhYmxlX2FsbCAlPiUgbGVmdF9qb2luKGFsbF9lcGksIGJ5ID0gYygiU2FtcGxlSUQxIiA9ICJTYW1wbGVJRCIpKSAlPiUgcmVuYW1lKGlkLnggPSBpZCkKR1NhbGxfZWRnZXMgPC0gR1NhbGxfZWRnZXMgJT4lIGxlZnRfam9pbihhbGxfZXBpLCBieSA9IGMoIlNhbXBsZUlEMiIgPSAiU2FtcGxlSUQiKSkgJT4lIHJlbmFtZShpZC55ID0gaWQpCkdTYWxsX2VkZ2VzIDwtIEdTYWxsX2VkZ2VzICU+JSBzZWxlY3QoaWQueCwgaWQueSwgR1Nfc2NvcmUpCgpTQW1fdGlkeSA8LSB0YmxfZ3JhcGgobm9kZXMgPSBhbGxfZXBpLCBlZGdlcyA9IEdTYWxsX2VkZ2VzLCBkaXJlY3RlZCA9IFQpCmBgYAoKIyMjIERlZmluaW5nICp2YXIqY29kZXM6IFNvdXRoIEFtZXJpY2EKYGBge3J9ClNBbV92YXJjb2Rlc19uZXR3b3JrIDwtIFNBbV90aWR5ICU+JSBhY3RpdmF0ZShlZGdlcykgJT4lIGZpbHRlcihHU19zY29yZSA+PSAwLjkpICU+JSAKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKyAKICBnZW9tX2VkZ2VfbGluayhjb2xvciA9ICJkYXJrZ3JleSIsIGFscGhhID0gMC41KSArIAogIGdlb21fbm9kZV9wb2ludChhZXMoZmlsbCA9IExvY2F0aW9uKSwgc2hhcGUgPSAyMSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMykgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvdW50cnlfY29sb3JzJExvY2F0aW9uLAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGNvdW50cnlfbGlzdCkgKwogIyBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBTYW1wbGVJRCksIHJlcGVsID0gVFJVRSkgKwogIGxhYnMoZWRnZV93aWR0aCA9ICJTYW1wbGVJRCIsCiAgICAgICBmaWxsID0gIiIpICsKICB0aGVtZV9ncmFwaCgpCgpzYXZlX3Bsb3QoInZpei9TQW1fdmFyY29kZV9uZXR3b3JrLnBuZyIsIFNBbV92YXJjb2Rlc19uZXR3b3JrLCBiYXNlX3dpZHRoID0gOCwgYmFzZV9oZWlnaHQgPSA2KQpTQW1fdmFyY29kZXNfbmV0d29yawpgYGAKCiMjIyBHZW5ldGljIFNpbWlsYXJpdHkgTmV0d29ya3M6IFNvdXRoIEFtZXJpY2EKYGBge3J9ClNBbV9yZWNvbWJpbmFudHNfbmV0d29yayA8LSBTQW1fdGlkeSAlPiUgI2ZpbHRlcihTYW1wbGVJRCAhPSAiRUNQZjAwNCIsIFNhbXBsZUlEICE9ICJFQ1BmMDExIikgJT4lIAogIGFjdGl2YXRlKGVkZ2VzKSAlPiUgZmlsdGVyKEdTX3Njb3JlID49IDAuNSkgJT4lIAogIGdncmFwaChsYXlvdXQgPSAiZnIiKSArIAogIGdlb21fZWRnZV9saW5rKGNvbG9yID0gImRhcmtncmV5IiwgYWxwaGEgPSAwLjUpICsgCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhmaWxsID0gTG9jYXRpb24pLCBzaGFwZSA9IDIxLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAzKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY291bnRyeV9jb2xvcnMkTG9jYXRpb24sCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gY291bnRyeV9saXN0KSArCiAjIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IFNhbXBsZUlEKSwgcmVwZWwgPSBUUlVFKSArCiAgbGFicyhlZGdlX3dpZHRoID0gIlNhbXBsZUlEIiwKICAgICAgIGZpbGwgPSAiIikgKwogIHRoZW1lX2dyYXBoKCkgCgpzYXZlX3Bsb3QoInZpei9TQW1fcmVjb21iaW5hbnRzX25ldHdvcmsucG5nIiwgU0FtX3JlY29tYmluYW50c19uZXR3b3JrLCBiYXNlX3dpZHRoID0gOCwgYmFzZV9oZWlnaHQgPSA2KQpTQW1fcmVjb21iaW5hbnRzX25ldHdvcmsKYGBgCgojIyMgR2VuZXRpYyBzaW1pbGFyaXR5OiAqdmFyKmNvZGVzIGFuZCBTb3V0aCBBbWVyaWNhCldlIGNhbiBhbHNvIGNhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIHNoYXJlZCB0eXBlcyBvciBnZW5ldGljIHNpbWlsYXJpdHkgb2YgdGhlIHZhcmNvZGVzIHdpdGggU291dGggQW1lcmljYW4gaXNvbGF0ZXMgdG8gY29ycm9ib3JhdGUgdGhlIG5ldHdvcmsgdmlzdWFsaXphdGlvbnMgKGFuZCBhZGQgYSBxdWFudGl0YXRpdmUgbWVhc3VyZSkuIFdlIG5lZWQgdG8gcmVjcmVhdGUgdGhlIHZhcmNvZGUgbWF0cml4IHdpdGggYWxsIDU0MyB0eXBlcyBpZGVudGlmaWVkIGluIFNvdXRoIEFtZXJpY2EuIApgYGB7ciBjcmVhdGUgdmFyY29kZSBtYXRyaXggZnJvbSBtYXRyaXhfYWxsfQp2YXJjb2RlX3ZlYyA8LSBlY3VfZXBpICU+JSBzZWxlY3QoU2FtcGxlSUQsIHZhcmNvZGUpCnZhcmNvZGVfdmVjJFNhbXBsZUlEIDwtIGFzLmZhY3Rvcih2YXJjb2RlX3ZlYyRTYW1wbGVJRCkKdmFyY29kZV92ZWMkdmFyY29kZSA8LSBhcy5mYWN0b3IodmFyY29kZV92ZWMkdmFyY29kZSkKCnZjMV9tYXRyaXhTQU0gPC0gbWF0cml4X2FsbFssIGNvbG5hbWVzKG1hdHJpeF9hbGwpICVpbiUgc3Vic2V0KHZhcmNvZGVfdmVjLCB2YXJjb2RlID09ICJ2YXJjb2RlMSIpJFNhbXBsZUlEXQp2YzJfbWF0cml4U0FNIDwtIG1hdHJpeF9hbGxbLCBjb2xuYW1lcyhtYXRyaXhfYWxsKSAlaW4lIHN1YnNldCh2YXJjb2RlX3ZlYywgdmFyY29kZSA9PSAidmFyY29kZTIiKSRTYW1wbGVJRF0KdmMzX21hdHJpeFNBTSA8LSBtYXRyaXhfYWxsWywgY29sbmFtZXMobWF0cml4X2FsbCkgJWluJSBzdWJzZXQodmFyY29kZV92ZWMsIHZhcmNvZGUgPT0gInZhcmNvZGUzIikkU2FtcGxlSURdCnZjNF9tYXRyaXhTQU0gPC0gbWF0cml4X2FsbFssIGNvbG5hbWVzKG1hdHJpeF9hbGwpICVpbiUgc3Vic2V0KHZhcmNvZGVfdmVjLCB2YXJjb2RlID09ICJ2YXJjb2RlNCIpJFNhbXBsZUlEXQp2YzVfbWF0cml4U0FNIDwtIG1hdHJpeF9hbGxbLCBjb2xuYW1lcyhtYXRyaXhfYWxsKSAlaW4lIHN1YnNldCh2YXJjb2RlX3ZlYywgdmFyY29kZSA9PSAidmFyY29kZTUiKSRTYW1wbGVJRF0KdmM2X21hdHJpeFNBTSA8LSBtYXRyaXhfYWxsWywgY29sbmFtZXMobWF0cml4X2FsbCkgJWluJSBzdWJzZXQodmFyY29kZV92ZWMsIHZhcmNvZGUgPT0gInZhcmNvZGU2IikkU2FtcGxlSURdCnZjN19tYXRyaXhTQU0gPC0gbWF0cml4X2FsbFssIGNvbG5hbWVzKG1hdHJpeF9hbGwpICVpbiUgc3Vic2V0KHZhcmNvZGVfdmVjLCB2YXJjb2RlID09ICJ2YXJjb2RlNyIpJFNhbXBsZUlEXQp2YzhfbWF0cml4U0FNIDwtIG1hdHJpeF9hbGxbLCBjb2xuYW1lcyhtYXRyaXhfYWxsKSAlaW4lIHN1YnNldCh2YXJjb2RlX3ZlYywgdmFyY29kZSA9PSAidmFyY29kZTgiKSRTYW1wbGVJRF0KdmM5X21hdHJpeFNBTSA8LSBtYXRyaXhfYWxsWywgY29sbmFtZXMobWF0cml4X2FsbCkgJWluJSBzdWJzZXQodmFyY29kZV92ZWMsIHZhcmNvZGUgPT0gInZhcmNvZGU5IikkU2FtcGxlSURdCgp2YzFfbWF0cml4U0FNX3N1bSA8LSByb3dTdW1zKHZjMV9tYXRyaXhTQU0pICU+JSBhcy5kYXRhLmZyYW1lKCkKdmMxX21hdHJpeFNBTV9zdW0gPC0gdmMxX21hdHJpeFNBTV9zdW0gJT4lIG11dGF0ZSh2YXJjb2RlMSA9IGlmZWxzZSguID4gMCwgMSwgMCkpICU+JSBzZWxlY3QodmFyY29kZTEpCnJvd25hbWVzKHZjMV9tYXRyaXhTQU1fc3VtKSA8LSByb3duYW1lcyh2YzFfbWF0cml4U0FNKQoKdmMyX21hdHJpeFNBTV9zdW0gPC0gcm93U3Vtcyh2YzJfbWF0cml4U0FNKSAlPiUgYXMuZGF0YS5mcmFtZSgpCnZjMl9tYXRyaXhTQU1fc3VtIDwtIHZjMl9tYXRyaXhTQU1fc3VtICU+JSBtdXRhdGUodmFyY29kZTIgPSBpZmVsc2UoLiA+IDAsIDEsIDApKSAlPiUgc2VsZWN0KHZhcmNvZGUyKQpyb3duYW1lcyh2YzJfbWF0cml4U0FNX3N1bSkgPC0gcm93bmFtZXModmMyX21hdHJpeFNBTSkKCnZjM19tYXRyaXhTQU1fc3VtIDwtIHJvd1N1bXModmMzX21hdHJpeFNBTSkgJT4lIGFzLmRhdGEuZnJhbWUoKQp2YzNfbWF0cml4U0FNX3N1bSA8LSB2YzNfbWF0cml4U0FNX3N1bSAlPiUgbXV0YXRlKHZhcmNvZGUzID0gaWZlbHNlKC4gPiAwLCAxLCAwKSkgJT4lIHNlbGVjdCh2YXJjb2RlMykKcm93bmFtZXModmMzX21hdHJpeFNBTV9zdW0pIDwtIHJvd25hbWVzKHZjM19tYXRyaXhTQU0pCgp2YzRfbWF0cml4U0FNX3N1bSA8LSBhcy5kYXRhLmZyYW1lKHZjNF9tYXRyaXhTQU0pICU+JSByZW5hbWVfYXQoInZjNF9tYXRyaXhTQU0iLCB+InZhcmNvZGU0IikKdmM1X21hdHJpeFNBTV9zdW0gPC0gYXMuZGF0YS5mcmFtZSh2YzVfbWF0cml4U0FNKSAlPiUgcmVuYW1lX2F0KCJ2YzVfbWF0cml4U0FNIiwgfiJ2YXJjb2RlNSIpCgp2YzZfbWF0cml4U0FNX3N1bSA8LSByb3dTdW1zKHZjNl9tYXRyaXhTQU0pICU+JSBhcy5kYXRhLmZyYW1lKCkKdmM2X21hdHJpeFNBTV9zdW0gPC0gdmM2X21hdHJpeFNBTV9zdW0gJT4lIG11dGF0ZSh2YXJjb2RlNiA9IGlmZWxzZSguID4gMCwgMSwgMCkpICU+JSBzZWxlY3QodmFyY29kZTYpCnJvd25hbWVzKHZjNl9tYXRyaXhTQU1fc3VtKSA8LSByb3duYW1lcyh2YzZfbWF0cml4U0FNKQoKdmM3X21hdHJpeFNBTV9zdW0gPC0gcm93U3Vtcyh2YzdfbWF0cml4U0FNKSAlPiUgYXMuZGF0YS5mcmFtZSgpCnZjN19tYXRyaXhTQU1fc3VtIDwtIHZjN19tYXRyaXhTQU1fc3VtICU+JSBtdXRhdGUodmFyY29kZTcgPSBpZmVsc2UoLiA+IDAsIDEsIDApKSAlPiUgc2VsZWN0KHZhcmNvZGU3KQpyb3duYW1lcyh2YzdfbWF0cml4U0FNX3N1bSkgPC0gcm93bmFtZXModmM3X21hdHJpeFNBTSkKCnZjOF9tYXRyaXhTQU1fc3VtIDwtIHJvd1N1bXModmM4X21hdHJpeFNBTSkgJT4lIGFzLmRhdGEuZnJhbWUoKQp2YzhfbWF0cml4U0FNX3N1bSA8LSB2YzhfbWF0cml4U0FNX3N1bSAlPiUgbXV0YXRlKHZhcmNvZGU4ID0gaWZlbHNlKC4gPiAwLCAxLCAwKSkgJT4lIHNlbGVjdCh2YXJjb2RlOCkKcm93bmFtZXModmM4X21hdHJpeFNBTV9zdW0pIDwtIHJvd25hbWVzKHZjOF9tYXRyaXhTQU0pCgp2YzlfbWF0cml4U0FNX3N1bSA8LSBhcy5kYXRhLmZyYW1lKHZjOV9tYXRyaXhTQU0pICU+JSByZW5hbWVfYXQoInZjOV9tYXRyaXhTQU0iLCB+InZhcmNvZGU5IikKCnZhcmNvZGVfbWF0cml4U0FNIDwtIGJpbmRfY29scyh2YzFfbWF0cml4U0FNX3N1bSwgdmMyX21hdHJpeFNBTV9zdW0sIHZjM19tYXRyaXhTQU1fc3VtLCB2YzRfbWF0cml4U0FNX3N1bSwgdmM1X21hdHJpeFNBTV9zdW0sIHZjNl9tYXRyaXhTQU1fc3VtLCB2YzdfbWF0cml4U0FNX3N1bSwgdmM4X21hdHJpeFNBTV9zdW0sIHZjOV9tYXRyaXhTQU1fc3VtKQpyb3duYW1lcyh2YXJjb2RlX21hdHJpeFNBTSkgPC0gcm93bmFtZXModmMxX21hdHJpeFNBTV9zdW0pCmBgYApUaGUgdG90YWwgbnVtYmVyIG9mIHR5cGVzIGluIGVhY2ggKnZhcipjb2RlIGlzIG5vdzogYHIga25pdHI6OmthYmxlKHZhcmNvZGVfbWF0cml4U0FNICU+JSBjb2xTdW1zKCkpICU+JSBrYWJsZV9zdHlsaW5nKClgICh3aGljaCBpcyBpZGVudGljYWwgdG8gYmVmb3JlIHdpdGggb25seSBOPTE5NSB0eXBlcykuCgpDcmVhdGUgdGhlIHZhcmNvZGUgYW5kIGNvdW50cnkgbWF0cml4CmBgYHtyIGNyZWF0ZSB2YXJjb2RlIGNvdW50cnkgbWF0cml4fQpjb3VudHJ5X21hdHJpeF90ZW1wIDwtIGNvdW50cnlfbWF0cml4ICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4oIkRCTGFfdHlwZSIpCnZhcmNvZGVfbWF0cml4U0FNX2ZpbmFsIDwtIHZhcmNvZGVfbWF0cml4U0FNICU+JSByb3duYW1lc190b19jb2x1bW4oIkRCTGFfdHlwZSIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZnRfam9pbihjb3VudHJ5X21hdHJpeF90ZW1wLCBieSA9ICJEQkxhX3R5cGUiKQp2YXJjb2RlX21hdHJpeFNBTV9maW5hbCA8LSB2YXJjb2RlX21hdHJpeFNBTV9maW5hbCAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJEQkxhX3R5cGUiKSAKCnZhcmNvZGVfbWF0cml4U0FNX2ZpbmFsIDwtIHZhcmNvZGVfbWF0cml4U0FNX2ZpbmFsICU+JSAgcmVuYW1lX2F0KCJ2YXJjb2RlMSIsIH4idmFyY29kZTEgKE49NDcpIikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbmFtZV9hdCgidmFyY29kZTIiLCB+InZhcmNvZGUyIChOPTQxKSIgKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVuYW1lX2F0KCJ2YXJjb2RlMyIsIH4idmFyY29kZTMgKE49NDApIikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbmFtZV9hdCgidmFyY29kZTQiLCB+InZhcmNvZGU0IChOPTQyKSIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW5hbWVfYXQoInZhcmNvZGU1IiwgfiJ2YXJjb2RlNSAoTj0zNCkiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVuYW1lX2F0KCJ2YXJjb2RlNiIsIH4idmFyY29kZTYgKE49NDUpIikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbmFtZV9hdCgidmFyY29kZTciLCB+InZhcmNvZGU3IChOPTQzKSIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW5hbWVfYXQoInZhcmNvZGU4IiwgfiJ2YXJjb2RlOCAoTj00MikiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVuYW1lX2F0KCJ2YXJjb2RlOSIsIH4idmFyY29kZTkgKE49MzUpIikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbmFtZV9hdCgiQ29sb21iaWEiLCB+IkNvbG9tYmlhIChOPTExMikiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVuYW1lX2F0KCJFY3VhZG9yIiwgfiJFY3VhZG9yIChOPTE5NSkiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVuYW1lX2F0KCJGcmVuY2ggR3VpYW5hIiwgfiJGcmVuY2ggR3VpYW5hIChOPTI0OSkiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVuYW1lX2F0KCJQZXJ1IiwgfiJQZXJ1IChOPTE1NykiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVuYW1lX2F0KCJWZW5lenVlbGEiLCB+IlZlbmV6dWVsYSAoTj0xNzYpIikKCnZhcmNvZGVfbWF0cml4U0FNX2ZpbmFsIDwtIHZhcmNvZGVfbWF0cml4U0FNX2ZpbmFsICU+JSBhcy5tYXRyaXgoKQpgYGAKQXMgd2UgZGlkIGJlZm9yZSwgZm9yIHRoZSBkaXJlY3Rpb25hbCBQVFMgYW1vbmcgdGhlICp2YXIqY29kZXMgYW5kIFNvdXRoIEFtZXJpY2FuIGlzb2xhdGVzLCB3ZSBjb25zaWRlciBib3RoIHRoZSAiZm9yd2FyZCIgYW5kICJyZXZlcnNlIiBkaXJlY3Rpb24gc2luY2UgdGhlcmUgaXMgbm90IHJlYWwgdGVtcG9yYWwgYXNwZWN0IHRvIHRoaXMgZGF0YXNldC4gVGhlIHNhbXBsaW5nIGxvY2F0aW9ucyBhbmQgc2FtcGxpbmcgdGltZXMgZGlmZmVyIGdyZWF0bHksIHNvIHdlIGFyZSBvbmx5IGludGVyZXN0ZWQgaW4gaWRlbnRpZnlpbmcgY2x1c3RlciBvZiBnZW5ldGljYWxseS1yZWxhdGVkIHBhcmFzaXRlcyBpbiBzcGFjZSBhbmQvb3IgdGltZSAoaS5lLiBub3QgcmVjZW50IHRyYW5zbWlzc2lvbiBldmVudHMgb3IgInJlYWwtdGltZSIgcmVjb21iaW5hdGlvbnMpLiAKCgpgYGB7ciBHZW5TaW0gdmFyY29kZXMgYW5kIFNBbX0KZ2VuU2ltX3ZhcmNvZGVTQU0gPC0gZ2VuZXRpY1NpbWlsYXJpdHkodCh2YXJjb2RlX21hdHJpeFNBTV9maW5hbCkpCkdTdGFibGVfdmFyY29kZVNBTSA8LSBHU21hdHJpeFRvVGFibGUoZ2VuU2ltX3ZhcmNvZGVTQU0pIAoKY291bnRyeU5zX2NvbG9ycyA8LSBsaXN0KExvY2F0aW9uID0gYygiQ29sb21iaWFcbihOPTExMikiID0gIiNmZGI0NjIiLCAiRWN1YWRvclxuKE49MTk1KSIgPSAiI2ZiODA3MiIsICJGcmVuY2ggR3VpYW5hXG4oTj0yNDkpIiA9ICIjYTZkODU0IiwgIlBlcnVcbihOPTE1NykiID0gIiM2NmMyYTUiLCAiVmVuZXp1ZWxhXG4oTj0xNzYpIiA9ICIjYmViYWRhIikpCgp2YXJjb2RlX2NvdW50cnlfdGlsZXBsb3QgPC0gR1N0YWJsZV92YXJjb2RlU0FNICU+JSBmaWx0ZXIoU2FtcGxlSUQxICVsaWtlJSAidmFyY29kZSIsICFTYW1wbGVJRDIgJWxpa2UlICJ2YXJjb2RlIikgJT4lIAogICAgbXV0YXRlKFNhbXBsZUlEMiA9IGNhc2Vfd2hlbihTYW1wbGVJRDIgPT0gIkNvbG9tYmlhIChOPTExMikiIH4iQ29sb21iaWFcbihOPTExMikiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTYW1wbGVJRDIgPT0gIkVjdWFkb3IgKE49MTk1KSIgfiJFY3VhZG9yXG4oTj0xOTUpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2FtcGxlSUQyID09ICJGcmVuY2ggR3VpYW5hIChOPTI0OSkiIH4gIkZyZW5jaCBHdWlhbmFcbihOPTI0OSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTYW1wbGVJRDIgPT0gIlBlcnUgKE49MTU3KSIgfiAiUGVydVxuKE49MTU3KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNhbXBsZUlEMiA9PSAiVmVuZXp1ZWxhIChOPTE3NikiIH4gIlZlbmV6dWVsYVxuKE49MTc2KSIpKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHggPSBTYW1wbGVJRDIsIHkgPSBTYW1wbGVJRDEsIGZpbGwgPSBTYW1wbGVJRDIpKSArCiAgICAgICAgZ2VvbV90aWxlKGFlcyhhbHBoYSA9IEdTX3Njb3JlKSkgKwogICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvdW50cnlOc19jb2xvcnMkTG9jYXRpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQ29sb21iaWFcbihOPTExMikiLCAiRWN1YWRvclxuKE49MTk1KSIsICJGcmVuY2ggR3VpYW5hXG4oTj0yNDkpIiwgIlBlcnVcbihOPTE1NykiLCAiVmVuZXp1ZWxhXG4oTj0xNzYpIiksCiAgICAgICAgICAgICAgICAgICAgICBndWlkZSA9ICJub25lIikgKwogICAgICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChHU19zY29yZSwgMikpKSArCiAgICAgICAgdGhlbWUoI2F4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApLAogICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsKICAgICAgICB0aGVtZV9jb3dwbG90KCkgKwogICAgICAgIGxhYnMoeCA9ICIiLAogICAgICAgICAgICAgeSA9ICIiLAogICAgICAgICAgICAgZmlsbCA9ICIiLAogICAgICAgICAgICAgYWxwaGEgPSBleHByZXNzaW9uKHBhc3RlKCJQIlsiVFMiXSwgIiBzY29yZSIpKSkKCnNhdmVfcGxvdCgidml6L3ZhcmNvZGVfY291bnRyeV90aWxlcGxvdC5wbmciLCB2YXJjb2RlX2NvdW50cnlfdGlsZXBsb3QsIGJhc2Vfd2lkdGggPSA4LCBiYXNlX2hlaWdodCA9IDQpCnZhcmNvZGVfY291bnRyeV90aWxlcGxvdApgYGAKCiMjIyMgT3V0YnJlYWsgKnZhcipjb2RlMTogZXZvbHV0aW9uYXJ5IGhpc3Rvcnkgb2YgdHlwZXMKYGBge3J9Cm91dGJyZWFrX3JlY29tYl9ldm8gPC0gdmFyY29kZV9tYXRyaXhTQU0gJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4oIkRCTGFfdHlwZSIpICU+JSAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoREJMYV90eXBlLCB2YXJjb2RlMSwgdmFyY29kZTMsIHZhcmNvZGU0LCB2YXJjb2RlNiwgdmFyY29kZTcpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcih2YXJjb2RlMSA+IDApIAoKb3V0YnJlYWtfcmVjb21iX2V2b19tYXQgPC0gb3V0YnJlYWtfcmVjb21iX2V2byAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJEQkxhX3R5cGUiKSAlPiUgYXMubWF0cml4KCkKCnJlY29tYl9uYW1lcyA8LSBkYXRhLmZyYW1lKHZhcmNvZGUgPSBjKCJ2YXJjb2RlMSIsICJ2YXJjb2RlMyIsICJ2YXJjb2RlNCIsICJ2YXJjb2RlNiIsICJ2YXJjb2RlNyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICB2YXJjb2RlX25hbWUgPSBjKCJ2YXJjb2RlMSIsICJ2YXJjb2RlMyIsICJ2YXJjb2RlNCIsICJ2YXJjb2RlNiIsICJ2YXJjb2RlNyIpKSAlPiUKICAgICAgICAgICAgIGNvbHVtbl90b19yb3duYW1lcygidmFyY29kZV9uYW1lIikKCmNvbG9yc19yZWNvbWIgPC0gbGlzdCh2YXJjb2RlID0gYygidmFyY29kZTEiID0gIiNmYjlhOTkiLCAidmFyY29kZTMiID0gIiM0OEIyNEYiLCAidmFyY29kZTQiID0gIiMzMGQ1YzgiLCAidmFyY29kZTYiID0gIiMzMDkwZDUiLCAidmFyY29kZTciID0gIiNDQUQ5M0YiKSkKCiNoZWF0bWFwX291dGJyZWFrX3JlY29tYiA8LSAKcGhlYXRtYXAodChvdXRicmVha19yZWNvbWJfZXZvX21hdCksIAogICAgICAgICBjb2wgPSBjKCJ3aGl0ZSIsICJibGFjayIpLCAKICAgICAgICAgYW5ub3RhdGlvbl9yb3cgPSByZWNvbWJfbmFtZXMsIAogICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGNvbG9yc19yZWNvbWIsCiAgICAgICAgIGZvbnRzaXplX3JvdyA9IDUsIAogICAgICAgICBmb250c2l6ZV9jb2wgPSA1LCAKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEYsIAogICAgICAgICBzaG93X3Jvd25hbWVzID0gRiwgCiAgICAgICAgICNmaWxlbmFtZSA9ICJ2aXovaGVhdG1hcF9vdXRicmVha3R5cGVzX3JlY29tYmluYW50cy5wbmciLAogICAgICAgICBsZWdlbmQgPSBGLCAKICAgICAgICAgdHJlZWhlaWdodF9jb2wgPSAwLAogICAgICAgICB3aWR0aCA9IDgsIAogICAgICAgICBoZWlnaHQgPSA0KQoKcGhlYXRtYXAodChvdXRicmVha19yZWNvbWJfZXZvX21hdCksIAogICAgICAgICBjb2wgPSBjKCJ3aGl0ZSIsICJibGFjayIpLCAKICAgICAgICAgYW5ub3RhdGlvbl9yb3cgPSByZWNvbWJfbmFtZXMsIAogICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGNvbG9yc19yZWNvbWIsCiAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEYsCiAgICAgICAgIGZvbnRzaXplX3JvdyA9IDUsIAogICAgICAgICBmb250c2l6ZV9jb2wgPSA1LCAKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEYsIAogICAgICAgICBzaG93X3Jvd25hbWVzID0gRiwgCiAgICAgICAgICNmaWxlbmFtZSA9ICJ2aXovaGVhdG1hcF9vdXRicmVha3R5cGVzX3JlY29tYmluYW50c19ub2NsdXN0ZXIucG5nIiwKICAgICAgICAgbGVnZW5kID0gRiwgCiAgICAgICAgIHRyZWVoZWlnaHRfY29sID0gMCwKICAgICAgICAgd2lkdGggPSA4LCAKICAgICAgICAgaGVpZ2h0ID0gNCkKCm91dGJyZWFrX3JlY29tYl9ldm8gJT4lIAogIG1lbHQoKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihEQkxhX3R5cGUsIHZhbHVlKSwgeSA9IHZhcmlhYmxlLCBmaWxsID0gZmFjdG9yKHZhbHVlKSkpICsgCiAgICBnZW9tX3RpbGUoY29sb3IgPSAiZ3JleSIpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIjAiID0gIndoaXRlIiwgIjEiID0gImJsYWNrIiksCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJhYnNlbmNlIiwgInByZXNlbmNlIikpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICAjdGhlbWVfY293cGxvdCgpICsKICAgIGxhYnMoeCA9ICJ2YXJjb2RlMSBEQkzOsSB0eXBlcyAoTj00NykiLAogICAgICAgICB5ID0gIiIsCiAgICAgICAgIGZpbGwgPSAiIikKYGBgIAoKYGBge3J9Cm91dGJyZWFrX2V2b2hpc3RvcnkgPC0gdmFyY29kZV9tYXRyaXhTQU1fZmluYWwgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4oIkRCTGFfdHlwZSIpICU+JSAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoREJMYV90eXBlLCBgdmFyY29kZTEgKE49NDcpYCwgYENvbG9tYmlhIChOPTExMilgLCBgUGVydSAoTj0xNTcpYCwgYFZlbmV6dWVsYSAoTj0xNzYpYCwgYEZyZW5jaCBHdWlhbmEgKE49MjQ5KWApICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihgdmFyY29kZTEgKE49NDcpYCA+IDApICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShzdW0gPSBgdmFyY29kZTEgKE49NDcpYCArIGBDb2xvbWJpYSAoTj0xMTIpYCArIGBQZXJ1IChOPTE1NylgICsgYFZlbmV6dWVsYSAoTj0xNzYpYCArIGBGcmVuY2ggR3VpYW5hIChOPTI0OSlgKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW5hbWVfYXQoInZhcmNvZGUxIChOPTQ3KSIsIH4idmFyY29kZTEiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW5hbWVfYXQoIkNvbG9tYmlhIChOPTExMikiLCB+IkNvbG9tYmlhIikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVuYW1lX2F0KCJQZXJ1IChOPTE1NykiLCB+IlBlcnUiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW5hbWVfYXQoIkZyZW5jaCBHdWlhbmEgKE49MjQ5KSIsIH4iRnJlbmNoIEd1aWFuYSIpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbmFtZV9hdCgiVmVuZXp1ZWxhIChOPTE3NikiLCB+IlZlbmV6dWVsYSIpCgpvdXRicmVha19ldm9oaXN0b3J5ICU+JSBncm91cF9ieShzdW0pICU+JSB0YWxseSgpCgojdmFyY29kZV9tYXRyaXhTQU1fZmluYWwgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCJEQkxhX3R5cGUiKSAlPiUgZmlsdGVyKERCTGFfdHlwZSAlaW4lIHN1YnNldChvdXRicmVha19ldm9oaXN0b3J5LCBzdW0gPT0gMSkkREJMYV90eXBlKSAlPiUgVmlldygpCgpvdXRicmVha19ldm9oaXN0b3J5X21hdCA8LSBvdXRicmVha19ldm9oaXN0b3J5ICU+JSBzZWxlY3QoLXN1bSkgJT4lIGNvbHVtbl90b19yb3duYW1lcygiREJMYV90eXBlIikgJT4lIGFzLm1hdHJpeCgpCgpldm9fbmFtZXMgPC0gZGF0YS5mcmFtZShgLmAgPSBjKCJ2YXJjb2RlMSIsICJDb2xvbWJpYSIsICJGcmVuY2ggR3VpYW5hIiwgIlBlcnUiLCAiVmVuZXp1ZWxhIiksCiAgICAgICAgICAgICAgICAgICAgICAgIGxvY2F0aW9uID0gYygidmFyY29kZTEiLCJDb2xvbWJpYSIsICJGcmVuY2ggR3VpYW5hIiwgIlBlcnUiLCAiVmVuZXp1ZWxhIikpICU+JSAKICAgICAgICAgICAgIGNvbHVtbl90b19yb3duYW1lcygibG9jYXRpb24iKQoKY29sb3JzX2V2byA8LSBsaXN0KGAuYCA9IGMoYHZhcmNvZGUxYCA9ICIjZmI4MDcyIiwgYENvbG9tYmlhYCA9ICIjZmRiNDYyIiwgYEZyZW5jaCBHdWlhbmFgID0gIiNhNmQ4NTQiLCBgUGVydWAgPSAiIzY2YzJhNSIsIGBWZW5lenVlbGFgID0gIiNiZWJhZGEiKSkKCiNoZWF0bWFwX291dGJyZWFrX1NBbSA8LSAKcGhlYXRtYXAodChvdXRicmVha19ldm9oaXN0b3J5X21hdCksIAogICAgICAgICBjb2wgPSBjKCJ3aGl0ZSIsICJibGFjayIpLCAKICAgICAgICAgYW5ub3RhdGlvbl9yb3cgPSBldm9fbmFtZXMsIAogICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGNvbG9yc19ldm8sCiAgICAgICAgIGZvbnRzaXplX3JvdyA9IDUsIAogICAgICAgICBmb250c2l6ZV9jb2wgPSA1LCAKICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEYsIAogICAgICAgICBzaG93X3Jvd25hbWVzID0gRiwgCiAgICAgICAgICNmaWxlbmFtZSA9ICJ2aXovaGVhdG1hcF9vdXRicmVha3R5cGVzLnBuZyIsCiAgICAgICAgIGxlZ2VuZCA9IEYsIAogICAgICAgICB0cmVlaGVpZ2h0X2NvbCA9IDAsCiAgICAgICAgIHdpZHRoID0gOCwgCiAgICAgICAgIGhlaWdodCA9IDQpCgpwaGVhdG1hcCh0KG91dGJyZWFrX2V2b2hpc3RvcnlfbWF0KSwgCiAgICAgICAgIGNvbCA9IGMoIndoaXRlIiwgImJsYWNrIiksIAogICAgICAgICBhbm5vdGF0aW9uX3JvdyA9IGV2b19uYW1lcywgCiAgICAgICAgIGFubm90YXRpb25fY29sb3JzID0gY29sb3JzX2V2bywKICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRiwgCiAgICAgICAgIGNsdXN0ZXJfY29scyA9IEYsIAogICAgICAgICBmb250c2l6ZV9yb3cgPSA1LCAKICAgICAgICAgZm9udHNpemVfY29sID0gNSwgCiAgICAgICAgIHNob3dfY29sbmFtZXMgPSBGLCAKICAgICAgICAgc2hvd19yb3duYW1lcyA9IEYsIAogICAgICAgICAjZmlsZW5hbWUgPSAidml6L2hlYXRtYXBfb3V0YnJlYWt0eXBlc19ub2NsdXN0ZXIucG5nIiwKICAgICAgICAgbGVnZW5kID0gRiwgCiAgICAgICAgIHRyZWVoZWlnaHRfY29sID0gMCwKICAgICAgICAgd2lkdGggPSA4LCAKICAgICAgICAgaGVpZ2h0ID0gNCkKCm91dGJyZWFrX2V2b2hpc3RvcnkgJT4lIHNlbGVjdCgtc3VtKSAlPiUgCiAgbWVsdCgpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKERCTGFfdHlwZSwgdmFsdWUpLCB5ID0gdmFyaWFibGUsIGZpbGwgPSBmYWN0b3IodmFsdWUpKSkgKyAKICAgIGdlb21fdGlsZShjb2xvciA9ICJncmV5IikgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiMCIgPSAid2hpdGUiLCAiMSIgPSAiYmxhY2siKSwKICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoImFic2VuY2UiLCAicHJlc2VuY2UiKSkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpICsKICAgICN0aGVtZV9jb3dwbG90KCkgKwogICAgbGFicyh4ID0gInZhcmNvZGUxIERCTM6xIHR5cGVzIChOPTQ3KSIsCiAgICAgICAgIHkgPSAiIiwKICAgICAgICAgZmlsbCA9ICIiKQpgYGAgCgojIyMjIEhlYXRtYXAgb2YgKnZhcipjb2RlMQpgYGB7cn0KdmMxXzQ3dHlwZXMgPC0gdmMxX21hdHJpeFNBTSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSAKICByb3duYW1lc190b19jb2x1bW4oIkRCTGFfdHlwZSIpICU+JSAKICBmaWx0ZXIoREJMYV90eXBlICVpbiUgb3V0YnJlYWtfcmVjb21iX2V2byREQkxhX3R5cGUpCgp2YzFfNDd0eXBlcyA8LSB2YzFfNDd0eXBlcyAlPiUgbGVmdF9qb2luKHNlbGVjdChvdXRicmVha19tZXRhZGF0YSwgREJMYV90eXBlLCBmcmVxKSwgYnkgPSAiREJMYV90eXBlIikgJT4lIGFycmFuZ2UoZGVzYyhmcmVxKSkKCnZjMV9tYXRyaXhfNDd0eXBlcyA8LSB2YzFfNDd0eXBlcyAlPiUgc2VsZWN0KC1mcmVxKSAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJEQkxhX3R5cGUiKSAlPiUgYXMubWF0cml4KCkgCgp2YXJjb2RlMV9saXN0IDwtIHZhcmNvZGVfbGlzdCAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCJTYW1wbGVJRCIpICU+JSBsZWZ0X2pvaW4oc2VsZWN0KGVjdV9lcGksIFNhbXBsZUlELCBDYXNlKSwgYnkgPSAiU2FtcGxlSUQiKSAlPiUgZmlsdGVyKFNhbXBsZUlEICVpbiUgbmFtZXModmMxXzQ3dHlwZXMpKSAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJDYXNlIikgJT4lIHNlbGVjdCgtU2FtcGxlSUQpCgp2YzFfbWF0cml4XzQ3dHlwZXMgPC0gdCh2YzFfbWF0cml4XzQ3dHlwZXMpCnJvd25hbWVzKHZjMV9tYXRyaXhfNDd0eXBlcykgPC0gcm93bmFtZXModmFyY29kZTFfbGlzdCkKCnZjMV9jb2wgPC0gbGlzdCh2YXJjb2RlID0gYygidmFyY29kZTEiID0gIiNmYjlhOTkiKSkKCiNoZWF0bWFwX291dGJyZWFrdmMxIDwtIApwaGVhdG1hcCh2YzFfbWF0cml4XzQ3dHlwZXMsIGNvbCA9IGMoIndoaXRlIiwgImJsYWNrIiksCiAgICAgICAgIGFubm90YXRpb25fcm93ID0gdmFyY29kZTFfbGlzdCwgCiAgICAgICAgIGFubm90YXRpb25fY29sb3JzID0gdmMxX2NvbCwgCiAgICAgICAgIGZvbnRzaXplX3JvdyA9IDUsIGZvbnRzaXplX2NvbCA9IDUsIAogICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGLCAKICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRiwgCiAgICAgICAgIGxlZ2VuZCA9IEYsIAogICAgICAgICB0cmVlaGVpZ2h0X2NvbCA9IDAsIAogICAgICAgICBzaG93X2NvbG5hbWVzID0gRiwKICAgICAgICAgc2hvd19yb3duYW1lcyA9IFQsIAogICAgICAgICAjZmlsZW5hbWUgPSAidml6L2hlYXRtYXBfdmFyY29kZTFfbm9jbHVzdGVyLnBuZyIsCiAgICAgICAgIHdpZHRoID0gOCwgCiAgICAgICAgIGhlaWdodCA9IDQpCgp2YzFfNDd0eXBlcyAlPiUgc2VsZWN0KC1mcmVxKSAlPiUgCiAgbWVsdChpZCA9ICJEQkxhX3R5cGUiKSAlPiUgCiAgcmVuYW1lX2F0KCJ2YXJpYWJsZSIsIH4iaXNvbGF0ZSIpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGVjdV9lcGksIFNhbXBsZUlELCBDYXNlKSwgYnkgPSBjKCJpc29sYXRlIiA9ICJTYW1wbGVJRCIpKSAlPiUgCiAgbXV0YXRlKENhc2UyID0gcGFzdGUoIkVDIixzcHJpbnRmKCIlMDJzIiwgc3Vic3RyKENhc2UsMyw1KSkpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihEQkxhX3R5cGUsIGRlc2ModmFsdWUpKSwgeSA9IENhc2UyLCBmaWxsID0gZmFjdG9yKHZhbHVlKSkpICsgCiAgICBnZW9tX3RpbGUoY29sb3IgPSAiZ3JleSIpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIjAiID0gIndoaXRlIiwgIjEiID0gImJsYWNrIiksCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJhYnNlbmNlIiwgInByZXNlbmNlIikpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgICAjdGhlbWVfY293cGxvdCgpICsKICAgIGxhYnMoeCA9ICJ2YXJjb2RlMSBEQkzOsSB0eXBlcyAoTj00NykiLAogICAgICAgICB5ID0gIkNhc2UiLAogICAgICAgICBmaWxsID0gIiIpCmBgYAoKIyMjIyBDb25zZXJ2YXRpb24gb2Ygb3V0YnJlYWsgdHlwZXMKYGBge3J9CiMgZnJlcXVlbmN5IG9mIHR5cGVzIGluIG91dGJyZWFrIGNsb25lCm91dGJyZWFrX21ldGFkYXRhICU+JSBzdW1tYXJpc2UobWluID0gbWluKGZyZXEpLCBtZWFuID0gbWVhbihmcmVxKSwgbWVkaWFuID0gbWVkaWFuKGZyZXEpLCBtYXggPSBtYXgoZnJlcSksIHN1bSA9IHN1bShmcmVxKSkgCgojc3VtIG9mIG9ic2VydmF0aW9ucyBvZiB0eXBlcyBpbiBvdXRicmVhayBjbG9uZQpvdXRicmVha19tZXRhZGF0YSAlPiUgZmlsdGVyKGZyZXEgPiAxKSAlPiUgc3VtbWFyaXNlKHN1bSA9IHN1bShmcmVxKSkgCgojIGZyZXF1ZW5jeSBvZiB0eXBlcyBpbiBvdXRicmVhayBjbG9uZSBleGNsdWRpbmcgc2luZ2xldG9ucyAKb3V0YnJlYWtfbWV0YWRhdGEgJT4lIGZpbHRlcihmcmVxID4gMSkgJT4lIHN1bW1hcmlzZShtaW4gPSBtaW4oZnJlcSksIG1lYW4gPSBtZWFuKGZyZXEpLCBtZWRpYW4gPSBtZWRpYW4oZnJlcSksIG1heCA9IG1heChmcmVxKSwgc3VtID0gc3VtKGZyZXEpKSAKCiMgZnJlcXVlbmN5IG9mIHR5cGVzIGluIG91dGJyZWFrIGNsb25lIGV4Y2x1ZGluZyBsb3cgZnJlcSB0eXBlcyAKb3V0YnJlYWtfbWV0YWRhdGEgJT4lIGZpbHRlcihmcmVxID4gNCkgJT4lIHN1bW1hcmlzZShtaW4gPSBtaW4oZnJlcSksIG1lYW4gPSBtZWFuKGZyZXEpLCBtZWRpYW4gPSBtZWRpYW4oZnJlcSksIG1heCA9IG1heChmcmVxKSwgc3VtID0gc3VtKGZyZXEpKQoKI2ZyZXF1ZW5jeSBvZiBvdXRicmVhayB0eXBlcyBpbiByZWNvbWJpbmFudCB2YXJjb2Rlcwp0eXBlZnJlcV9vdXRicmVha19yZWNvbWIgPC0gb3V0YnJlYWtfbWV0YWRhdGEgJT4lIGxlZnRfam9pbih2YzNfbWF0cml4U0FNICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dTdW1zKCkgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVuYW1lX2F0KCIuIiwgfiAiZnJlcV92YzMiKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93bmFtZXNfdG9fY29sdW1uKCJEQkxhX3R5cGUiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIkRCTGFfdHlwZSIpCgp0eXBlZnJlcV9vdXRicmVha19yZWNvbWIgPC0gdHlwZWZyZXFfb3V0YnJlYWtfcmVjb21iICU+JSBsZWZ0X2pvaW4odmM0X21hdHJpeFNBTSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbmFtZV9hdCgiLiIsIH4gImZyZXFfdmM0IikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4oIkRCTGFfdHlwZSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIkRCTGFfdHlwZSIpCgp0eXBlZnJlcV9vdXRicmVha19yZWNvbWIgPC0gdHlwZWZyZXFfb3V0YnJlYWtfcmVjb21iICU+JSBsZWZ0X2pvaW4odmM2X21hdHJpeFNBTSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd1N1bXMoKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbmFtZV9hdCgiLiIsIH4gImZyZXFfdmM2IikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4oIkRCTGFfdHlwZSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIkRCTGFfdHlwZSIpCgp0eXBlZnJlcV9vdXRicmVha19yZWNvbWIgPC0gdHlwZWZyZXFfb3V0YnJlYWtfcmVjb21iICU+JSBsZWZ0X2pvaW4odmM3X21hdHJpeFNBTSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd1N1bXMoKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbmFtZV9hdCgiLiIsIH4gImZyZXFfdmM3IikgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3duYW1lc190b19jb2x1bW4oIkRCTGFfdHlwZSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIkRCTGFfdHlwZSIpCgp0eXBlZnJlcV9vdXRicmVha19yZWNvbWIgPC0gdHlwZWZyZXFfb3V0YnJlYWtfcmVjb21iICU+JSBtdXRhdGUoZnJlcV9yZWNvbWIgPSBmcmVxX3ZjMyArIGZyZXFfdmM0ICsgZnJlcV92YzYgKyBmcmVxX3ZjNykKCiNmcmVxdWVuY3kgb2Ygb3V0YnJlYWsgdHlwZXMgaW4gcmVjb21iaW5hbnQgdmFyY29kZXMgKDMsNCw2LDcpCnR5cGVmcmVxX291dGJyZWFrX3JlY29tYiAlPiUgc3VtbWFyaXNlKG1pbiA9IG1pbihmcmVxX3JlY29tYiksIG1lYW4gPSBtZWFuKGZyZXFfcmVjb21iKSwgbWVkaWFuID0gbWVkaWFuKGZyZXFfcmVjb21iKSwgbWF4ID0gbWF4KGZyZXFfcmVjb21iKSwgc3VtID0gc3VtKGZyZXFfcmVjb21iKSkgCgojaG93IG1hbnkgb2YgdGhlIDQ3IERCTGEgdHlwZXMgd2VyZSBpZGVudGlmaWVkIGluIHRoZSByZWNvbWJpbmFudHM/CnR5cGVmcmVxX291dGJyZWFrX3JlY29tYiAlPiUgZmlsdGVyKGZyZXFfcmVjb21iID4gMCkgJT4lIG5yb3coKQoKI2hvdyBtYW55IG9mIHRoZSA0NyBEQkxhIHR5cGVzIHdlcmUgaWRlbnRpZmllZCBpbiBlYWNoIHJlY29tYmluYW50PyAoYW5kIHByb3BvcnRpb24pCnR5cGVmcmVxX291dGJyZWFrX3JlY29tYiAlPiUgZmlsdGVyKGZyZXFfdmMzID4gMCkgJT4lIG5yb3coKSAKMjcvNDcKdHlwZWZyZXFfb3V0YnJlYWtfcmVjb21iICU+JSBmaWx0ZXIoZnJlcV92YzQgPiAwKSAlPiUgbnJvdygpIAoyNi80Nwp0eXBlZnJlcV9vdXRicmVha19yZWNvbWIgJT4lIGZpbHRlcihmcmVxX3ZjNiA+IDApICU+JSBucm93KCkgCjE3LzQ3CnR5cGVmcmVxX291dGJyZWFrX3JlY29tYiAlPiUgZmlsdGVyKGZyZXFfdmM3ID4gMCkgJT4lIG5yb3coKSAKMjYvNDcKYGBgCgojIyMjIENvbnNlcnZhdGlvbiBvZiBFY3VhZG9yaWFuIHR5cGVzCmBgYHtyfQp0eXBlZnJlcV9lY3UgPC0gYmluYXJ5X2VjdSAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCJEQkxhX3R5cGUiKSAlPiUgcm93U3VtcygpICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigiREJMYV90eXBlIikgJT4lIHJlbmFtZV9hdCgiLiIsIH4iZnJlcV9lY3UiKQoKdHlwZWZyZXFfYWxsIDwtIGJpbmFyeV9hbGwgJT4lIGNvbHVtbl90b19yb3duYW1lcygiREJMYV90eXBlIikgJT4lIHJvd1N1bXMoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSByb3duYW1lc190b19jb2x1bW4oIkRCTGFfdHlwZSIpICU+JSByZW5hbWVfYXQoIi4iLCB+ImZyZXFfYWxsIikKCnR5cGVmcmVxX2NvbnNlcnZhdGlvbiA8LSB0eXBlZnJlcV9lY3UgJT4lIGxlZnRfam9pbih0eXBlZnJlcV9hbGwsIGJ5ID0gIkRCTGFfdHlwZSIpCnR5cGVmcmVxX2NvbnNlcnZhdGlvbiA8LSB0eXBlZnJlcV9jb25zZXJ2YXRpb24gJT4lIG11dGF0ZShmcmVxX2NvbnRpbmVudCA9IGZyZXFfYWxsIC0gZnJlcV9lY3UpCgojaG93IG1hbnkgaW5kZXBlbmRlbnQgb2JzZXJ2YXRpb25zIG9mIEVjdWFkb3JpYW4gdHlwZXMgaW4gU291dGggQW1lcmljYT8gMjEzMAp0eXBlZnJlcV9jb25zZXJ2YXRpb24gJT4lIGZpbHRlcihmcmVxX2NvbnRpbmVudCA+IDApICU+JSBzdW1tYXJpc2Uoc3VtID0gc3VtKGZyZXFfY29udGluZW50KSkKCiNudW1iZXIgb2Ygc2luZ2xldG9ucyBpbiBFY3UgdGhhdCBhcmUgc2VlbiBpbiBTb3V0aCBBbWVyaWNhCnR5cGVmcmVxX2NvbnNlcnZhdGlvbiAlPiUgZmlsdGVyKGZyZXFfZWN1ID09IDEpICU+JSBuX2Rpc3RpbmN0KCkKdHlwZWZyZXFfY29uc2VydmF0aW9uICU+JSBmaWx0ZXIoZnJlcV9lY3UgPT0gMSAmIGZyZXFfY29udGluZW50ID4gMCkgJT4lIG5fZGlzdGluY3QoKQoKZWN1dHlwZWZyZXFfcGxvdCA8LSB0eXBlZnJlcV9jb25zZXJ2YXRpb24gJT4lIAogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoREJMYV90eXBlLCBmcmVxX2VjdSksIAogICAgICAgICAgICAgeSA9IGZyZXFfY29udGluZW50LCAKICAgICAgICAgICAgIGNvbG9yID0gY3V0KGZyZXFfZWN1LCBjKDAsIDEsIDEwLCAyMCwgMzAsIDQwLCA1MCwgNjApKSkpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2NhbGVzOjpwcmV0dHlfYnJlYWtzKG4gPSAxMCkpICsKICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikgKwogICAgbGFicyh4ID0gIkVjdWFkb3JpYW4gREJMzrEgdHlwZXMgKE49MTk1KSIsCiAgICAgICAgIHkgPSAiRnJlcXVlbmN5IGluIFNvdXRoIEFtZXJpY2EgKE49MTI4IGlzb2xhdGVzKSIsCiAgICAgICAgIGNvbG9yID0gIkZyZXF1ZW5jeSBpbiBFY3VhZG9yIikgKwogICAgdGhlbWVfY293cGxvdCgpICsKICAgIGJhY2tncm91bmRfZ3JpZChtYWpvciA9ICJ5IikgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpIAoKc2F2ZV9wbG90KCJ2aXovZWN1dHlwZXNfY29uc2VydmF0aW9uX2ZyZXEucG5nIiwgZWN1dHlwZWZyZXFfcGxvdCwgYmFzZV93aWR0aCA9IDEwLCBiYXNlX2hlaWdodCA9IDYpCmVjdXR5cGVmcmVxX3Bsb3QKYGBgCgoKIyMgTmVpZ2hib3ItSm9pbmluZyBUcmVlIEFuYWx5c2lzCiMjIyMgU291dGggQW1lcmljYQpOb3cgSSB3aWxsIHVzZSB0aGUgYGFwZWAgYW5kIGBnZ3RyZWVgIHBhY2thZ2UgdG8gY3JlYXRlIGFuIHVucm9vdGVkIG5laWdoYm9yLWpvaW5pbmcgdHJlZS4gV2Ugd2lsbCB1c2UgMS1HUyB0byByZXByZXNlbnQgZ2VuZXRpYyBkaXN0YW5jZSAoaS5lLiBQVEQgYXMgaW4gW1JvdWdlcm9uIGV0IGFsIDIwMTddKGh0dHBzOi8vb25saW5lbGlicmFyeS53aWxleS5jb20vZG9pL2Z1bGwvMTAuMTAwMi9lY2UzLjM0MjUpKS4gVGhlcmVmb3JlLCBhIHZhbHVlIG9mIDAgd291bGQgaW5kaWNhdGUgaWRlbnRpY2FsIHJlcGVydG9pcmVzLCBpLmUuIDAgZ2VuZXRpYyBkaXN0YW5jZSBmcm9tIGVhY2ggb3RoZXIuIEZvciBmdXR1cmUgcmVmZXJlbmNlIEkgdXNlZCB0aGlzIFt0dXRvcmlhbF0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy92aWduZXR0ZXMvZ2d0cmVlL2luc3QvZG9jL3RyZWVNYW5pcHVsYXRpb24uaHRtbCkuIApgYGB7ciBOSnRyZWUgU0FtfQpTQW1fdHJlZV9HUyA8LSBuaihhcy5kaXN0KDEgLSBnZW5TaW1fYWxsKSkKU0FtX3RyZWVfR1MgPC0gbGFkZGVyaXplKFNBbV90cmVlX0dTKQoKZ3JvdXBJbmZvIDwtIGFsbF9lcGkgJT4lIHNlbGVjdChTYW1wbGVJRCwgTG9jYXRpb24pICU+JSBncm91cF9ieShMb2NhdGlvbikgJT4lIGRvKHRheGFfbGlzdCA9IC4kU2FtcGxlSUQpCmdyb3VwcyA8LSBsYXBwbHkoZ3JvdXBJbmZvJHRheGFfbGlzdCwgYXMudmVjdG9yKQpuYW1lcyhncm91cHMpIDwtIGdyb3VwSW5mbyRMb2NhdGlvbgoKU0FtX3RyZWVfR1MgPC0gZ3JvdXBPVFUoU0FtX3RyZWVfR1MsIGdyb3VwcykKClNBbV9jb2xzIDwtIGMoIiNmZGI0NjIiLCAiI2ZiODA3MiIsICIjYTZkODU0IiwgIiM2NmMyYTUiLCAiI2JlYmFkYSIpCm5hbWVzKFNBbV9jb2xzKSA8LSBuYW1lcyhncm91cHMpCgpTQW1fTkp0cmVlIDwtIGdndHJlZShTQW1fdHJlZV9HUywgYWVzKGNvbG9yID0gZ3JvdXApLCBicmFuY2gubGVuZ3RoID0gIm5vbmUiLCBsYXlvdXQgPSAiY2lyY3VsYXIiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IFNBbV9jb2xzLAogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBuYW1lcyhTQW1fY29scykpICsKICBnZW9tX3RpcHBvaW50KHNpemUgPSAxKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKc2F2ZV9wbG90KCJ2aXovU0FtX05KdHJlZS5wbmciLCBTQW1fTkp0cmVlKQpTQW1fTkp0cmVlCmBgYAoKIyMgRXBpZGVtaW9sb2d5IEFuYWx5c2lzCk5vdyB3ZSB3YW50IHRvIGNoYXJhY3Rlcml6ZSB0aGUgZXBpZGVtaW9sb2d5IHN1cnJvdW5kaW5nIHRoZSBvdXRicmVhayBjYXNlcyBhbmQgdGhvc2UgcG9zdC1vdXRicmVhay4gQXJlIHRoZXJlIGFueSBwYXJ0aWN1bGFyIHJpc2sgZmFjdG9ycyAobG9jYXRpb24sIGFnZSwgc2V4KT8gVW5kb3VidGVkbHksIGxvY2F0aW9uIHdpbGwgYmUgYSByaXNrIGZhY3RvciwgYnV0IGxldCdzIHF1YW50aWZ5IHRoaXMuIFRvIGV4cGxvcmUgdGhlIGRlbW9ncmFwaGljcyBvZiB0aGUgaW5kaXZpZHVhbHMgaGFyYm9yaW5nIGNhc2VzIHdlIGZvY3VzIG9uIHR3byBicm9hZCBzdHJhdGlmaWNhdGlvbiBncm91cHM6IAoxLiAgT3V0YnJlYWsgY2FzZXMgKE49MzApCjIuICBOb24tb3V0YnJlYWsgY2FzZXMgKE49MjgpLgoKV2UgYWxzbyBmb2N1cyBvbiB0aGUgZm9sbG93aW5nIHN0cmF0aWZpY2F0aW9uIGdyb3VwcyBiYXNlZCBvbiBvdXIgKnZhcipjb2RlIGdlbmV0aWMgZGF0YToKMS4gQ2FzZXMgY2F1c2VkIGJ5IG91dGJyZWFrIGNsb25lICgqdmFyKmNvZGUxIGluIDIwMTMpCjIuIENhc2VzIGNhdXNlZCBieSAqdmFyKmNvZGUxICoqYWZ0ZXIqKiB0aGUgb3V0YnJlYWsgKDIwMTQgb3IgMjAxNSkKMy4gQ2FzZXMgY2F1c2VkIGJ5IHJlY29tYmluYW50cyBvZiAqdmFyKmNvZGUxIAo0LiBDYXNlcyBjYXVzZWQgYnkgZGlmZmVyZW50ICp2YXIqY29kZXMuCgojIyMgV2hhdCBhcmUgdGhlIGRlbW9ncmFwaGljIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgNTAgc3R1ZHkgcGFydGljaXBhbnRzIHdpdGggZXBpIGRhdGE/CipOb3RlKiB3ZSBkb24ndCBoYXZlIGFnZSBhbmQgc2V4IGRhdGEgZm9yIGByIGVjdV9lcGkgJT4lIGZpbHRlcihpcy5uYShBZ2UpICYgaXMubmEoU2V4KSkgJT4lIHRhbGx5KCkgJT4lIGFzLmludGVnZXIoKWAgcGFydGljaXBhbnRzLgpgYGB7cn0KZWN1X2VwaSAlPiUgZmlsdGVyKCFpcy5uYShBZ2UpICYgIWlzLm5hKFNleCkpICU+JSBzdW1tYXJpemUobWluID0gbWluKEFnZSksIG1lZCA9IG1lZGlhbihBZ2UpLCBhdmcgPSBtZWFuKEFnZSksIG1heCA9IG1heChBZ2UpKSAKZWN1X2VwaSAlPiUgZmlsdGVyKCFpcy5uYShBZ2UpICYgIWlzLm5hKFNleCkpICU+JSBncm91cF9ieShTZXgpICU+JSB0YWxseSgpICAKYGBgCgojIyMgV2hhdCBhcmUgdGhlIGRlbW9ncmFwaGljIGNoYXJhY3RlcmlzdGljcyBvZiBpbmRpdmlkdWFscyB3aXRoICpQLiBmYWxjaXBhcnVtKiBjYXNlcyBkdXJpbmcgdGhlIG91dGJyZWFrPwpgYGB7cn0gCmVjdV9lcGkgJT4lIGZpbHRlcihZZWFyPT0gIjIwMTMiKSAlPiUgZ3JvdXBfYnkoU2V4KSAlPiUgdGFsbHkoKSAKCmVjdV9lcGkgJT4lIGZpbHRlcihZZWFyID09ICIyMDEzIiwgIWlzLm5hKEFnZSkpICU+JSBzdW1tYXJpemUobWluID0gbWluKEFnZSksIG1lZCA9IG1lZGlhbihBZ2UpLCBhdmcgPSBtZWFuKEFnZSksIG1heCA9IG1heChBZ2UpKSAKZWN1X2VwaSAlPiUgZmlsdGVyKFllYXIgPT0gIjIwMTMiLCAhaXMubmEoQWdlKSkgJT4lIGdyb3VwX2J5KFNleCkgJT4lIHN1bW1hcml6ZShtaW4gPSBtaW4oQWdlKSwgbWVkID0gbWVkaWFuKEFnZSksIGF2ZyA9IG1lYW4oQWdlKSwgbWF4ID0gbWF4KEFnZSkpICAKYGBgClRoZSBzdW1tYXJ5IHN0YXRpc3RpY3MgZm9yIHRoZSBhZ2VzIG9mIGluZGl2aWR1YWxzIHdpdGggY2FzZXMgZHVyaW5nIHRoZSBvdXRicmVhayBpczoKYHIga25pdHI6OmthYmxlKGVjdV9lcGkgJT4lIGZpbHRlcihZZWFyID09ICIyMDEzIiwgIWlzLm5hKEFnZSkpICU+JSBzdW1tYXJpemUobWluID0gbWluKEFnZSksIG1lZCA9IG1lZGlhbihBZ2UpLCBhdmcgPSBtZWFuKEFnZSksIG1heCA9IG1heChBZ2UpKSkgJT4lIGthYmxlX3N0eWxpbmcoKWAKClRoZSBzdW1tYXJ5IHN0YXRpc3RpY3MgZm9yIHRoZSBhZ2VzIG9mIGluZGl2aWR1YWxzIHdpdGggY2FzZXMgZHVyaW5nIHRoZSBvdXRicmVhaywgc3RyYXRpZmllZCBieSBzZXggaXM6CmByIGtuaXRyOjprYWJsZShlY3VfZXBpICU+JSBmaWx0ZXIoWWVhciA9PSAiMjAxMyIsICFpcy5uYShBZ2UpKSAlPiUgZ3JvdXBfYnkoU2V4KSAlPiUgc3VtbWFyaXplKG1pbiA9IG1pbihBZ2UpLCBtZWQgPSBtZWRpYW4oQWdlKSwgYXZnID0gbWVhbihBZ2UpLCBtYXggPSBtYXgoQWdlKSkpICU+JSAga2FibGVfc3R5bGluZygpYAoKIyMjIFdhcyB0aGVyZSBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gdGhlIGRpc3RyaWJ1dGlvbiBvZiBhZ2VzIG9mIG1hbGVzIG9yIGZlbWFsZXMgd2l0aCBjYXNlcyBkdXJpbmcgdGhlIG91dGJyZWFrPwpgYGB7cn0KZWN1X2VwaSAlPiUgZmlsdGVyKFllYXIgPT0gIjIwMTMiLCAhaXMubmEoQWdlKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IFNleCwgeSA9IEFnZSkpICsgZ2VvbV9ib3hwbG90KCkgKyBnZW9tX3BvaW50KCkgKyBzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gIndpbGNveC50ZXN0IiwgcGFpcmVkID0gRikKCgp3aWxjb3gudGVzdChBZ2UgfiBTZXgsIGRhdGEgPSBlY3VfZXBpICU+JSBmaWx0ZXIoT3V0YnJlYWsgPT0gIk91dGJyZWFrMjAxMyIsICFpcy5uYShBZ2UpKSwgZXhhY3QgPSBGLCBwYWlyZWQgPSBGKQpgYGAKVGhlcmUgd2FzIG5vIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gdGhlIGFnZXMgb2YgbWFsZXMgb3IgZmVtYWxlcyB3aG8gaGFkICpQLiBmYWxjaXBhcnVtKiBjYXNlcyBkdXJpbmcgdGhlIG91dGJyZWFrIChwID0gMC4zOCkuIAoKIyMjIFdoYXQgYXJlIHRoZSBkZW1vZ3JhcGhpYyBjaGFyYWN0ZXJpc3RpY3Mgb2YgaW5kaXZpZHVhbHMgd2l0aCAqUC4gZmFsY2lwYXJ1bSogY2FzZXMgZHVyaW5nIGFuZCBhZnRlciB0aGUgb3V0YnJlYWs/CmBgYHtyfQplY3VfZXBpICU+JSBncm91cF9ieShPdXRicmVha0JpbmFyeSkgJT4lIHRhbGx5KCkgCmVjdV9lcGkgJT4lIGdyb3VwX2J5KE91dGJyZWFrQmluYXJ5LCBTZXgpICU+JSB0YWxseSgpICAKZWN1X2VwaSAlPiUgZ3JvdXBfYnkoT3V0YnJlYWtCaW5hcnksIGlzLm5hKEFnZSkpICU+JSB0YWxseSgpIAplY3VfZXBpICU+JSBmaWx0ZXIoIWlzLm5hKFNleCkgJiAhaXMubmEoQWdlKSkgJT4lIGdyb3VwX2J5KE91dGJyZWFrQmluYXJ5KSAlPiUgdGFsbHkoKSAKZWN1X2VwaSAlPiUgZmlsdGVyKCFpcy5uYShBZ2UpKSAlPiUgZ3JvdXBfYnkoT3V0YnJlYWtCaW5hcnkpICU+JSBzdW1tYXJpemUobWluID0gbWluKEFnZSksIG1lZCA9IG1lZGlhbihBZ2UpLCBhdmcgPSBtZWFuKEFnZSksIG1heCA9IG1heChBZ2UpKSAKZWN1X2VwaSAlPiUgZmlsdGVyKCFpcy5uYShBZ2UpKSAlPiUgZ3JvdXBfYnkoT3V0YnJlYWtCaW5hcnksIFNleCkgJT4lIHN1bW1hcml6ZShtaW4gPSBtaW4oQWdlKSwgbWVkID0gbWVkaWFuKEFnZSksIGF2ZyA9IG1lYW4oQWdlKSwgbWF4ID0gbWF4KEFnZSkpIApgYGAKV2UgaGF2ZSBkYXRhIGZvciBhZ2UgYW5kIHNleCBmb3IgdGhlIGZvbGxvd2luZyBwYXJ0aWNpcGFudHM6IGByIGtuaXRyOjprYWJsZShlY3VfZXBpICU+JSBmaWx0ZXIoIWlzLm5hKFNleCkgJiAhaXMubmEoQWdlKSkgJT4lIGdyb3VwX2J5KE91dGJyZWFrQmluYXJ5KSAlPiUgdGFsbHkoKSkgJT4lIGthYmxlX3N0eWxpbmcoKWAgCgpUaGUgc3VtbWFyeSBzdGF0aXN0aWNzIGZvciB0aGUgYWdlcyBvZiBpbmRpdmlkdWFscyB3aXRoIGNhc2VzIGR1cmluZyBhbmQgYWZ0ZXIgdGhlIG91dGJyZWFrIGlzOiBgciBrbml0cjo6a2FibGUoZWN1X2VwaSAlPiUgZmlsdGVyKCFpcy5uYShBZ2UpKSAlPiUgZ3JvdXBfYnkoT3V0YnJlYWtCaW5hcnkpICU+JSBzdW1tYXJpemUobWluID0gbWluKEFnZSksIG1lZCA9IG1lZGlhbihBZ2UpLCBhdmcgPSBtZWFuKEFnZSksIG1heCA9IG1heChBZ2UpKSkgJT4lIGthYmxlX3N0eWxpbmcoKWAgCgpUaGUgc3VtbWFyeSBzdGF0aXN0aWNzIGZvciB0aGUgYWdlcyBvZiBpbmRpdmlkdWFscyB3aXRoIGNhc2VzIGR1cmluZyBhbmQgYWZ0ZXIgdGhlIG91dGJyZWFrLCBzdHJhdGlmaWVkIGJ5IHNleCBpczogYHIga25pdHI6OmthYmxlKGVjdV9lcGkgJT4lIGZpbHRlcighaXMubmEoQWdlKSkgJT4lIGdyb3VwX2J5KE91dGJyZWFrQmluYXJ5LCBTZXgpICU+JSBzdW1tYXJpemUobWluID0gbWluKEFnZSksIG1lZCA9IG1lZGlhbihBZ2UpLCBhdmcgPSBtZWFuKEFnZSksIG1heCA9IG1heChBZ2UpKSkgJT4lIGthYmxlX3N0eWxpbmcoKWAgCgojIyMgV2FzIHRoZXJlIGEgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiB0aGUgYWdlcyBvZiBpbmRpdmlkdWFscyB3aXRoICpQLiBmYWxjaXBhcnVtKiBjYXNlcyBkdXJpbmcgYW5kIGFmdGVyIHRoZSBvdXRicmVhaz8KYGBge3J9CmVjdV9lcGkgJT4lIGZpbHRlcighaXMubmEoQWdlKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IE91dGJyZWFrQmluYXJ5LCB5ID0gQWdlKSkgKyBnZW9tX2JveHBsb3QoKSArIGdlb21fcG9pbnQoKSArIHN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAid2lsY294LnRlc3QiLCBwYWlyZWQgPSBGKQoKd2lsY294LnRlc3QoQWdlIH4gT3V0YnJlYWtCaW5hcnksIGRhdGEgPSBlY3VfZXBpICU+JSBmaWx0ZXIoIWlzLm5hKEFnZSkpLCBleGFjdCA9IEYsIHBhaXJlZCA9IEYpCmBgYApUaGVyZSB3YXMgbm8gc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiB0aGUgYWdlcyBvZiBpbmRpdmlkdWFscyB3aG8gaGFkICpQLiBmYWxjaXBhcnVtKiBjYXNlcyBkdXJpbmcgb3IgYWZ0ZXIgdGhlIG91dGJyZWFrIChwID0gMC4zOSkuCgojIyMgV2FzIHRoZXJlIGEgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiB0aGUgYWdlcyBvZiBtYWxlcyBvciBmZW1hbGVzIHdpdGggKlAuIGZhbGNpcGFydW0qIGNhc2VzIGFmdGVyIHRoZSBvdXRicmVhaz8KYGBge3J9CmVjdV9lcGkgJT4lIGZpbHRlcihPdXRicmVha0JpbmFyeSA9PSAiTm90T3V0YnJlYWsyMDEzIiwgIWlzLm5hKEFnZSkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBTZXgsIHkgPSBBZ2UpKSArIGdlb21fYm94cGxvdCgpICsgZ2VvbV9wb2ludCgpICsgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsIHBhaXJlZCA9IEYpCgp3aWxjb3gudGVzdChBZ2UgfiBTZXgsIGRhdGEgPSBlY3VfZXBpICU+JSBmaWx0ZXIoT3V0YnJlYWtCaW5hcnkgPT0gIk5vdE91dGJyZWFrMjAxMyIsICFpcy5uYShBZ2UpKSwgZXhhY3QgPSBGLCBwYWlyZWQgPSBGKQpgYGAKVGhlcmUgd2FzIG5vIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gdGhlIGFnZXMgb2YgbWFsZXMgb3IgZmVtYWxlcyB3aG8gaGFkICpQLiBmYWxjaXBhcnVtKiBjYXNlcyBhZnRlciB0aGUgb3V0YnJlYWsgKHAgPSAwLjc3KS4KCiMjIyBXYXMgdGhlcmUgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIHRoZSBhZ2VzIG9mIG1hbGVzIG9yIGZlbWFsZXMgd2l0aCAqUC4gZmFsY2lwYXJ1bSogY2FzZXMgZHVyaW5nIG9yIGFmdGVyIHRoZSBvdXRicmVhaz8KYGBge3J9CmVjdV9lcGkgJT4lIGZpbHRlcighaXMubmEoQWdlKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IFNleCwgeSA9IEFnZSkpICsgZ2VvbV9ib3hwbG90KCkgKyBnZW9tX3BvaW50KCkgKyBzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gIndpbGNveC50ZXN0IiwgcGFpcmVkID0gRikKCndpbGNveC50ZXN0KEFnZSB+IFNleCwgZGF0YSA9IGVjdV9lcGkgJT4lIGZpbHRlcighaXMubmEoQWdlKSksIGV4YWN0ID0gRiwgcGFpcmVkID0gRikKYGBgClRoZXJlIHdhcyBubyBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIHRoZSBhZ2VzIG9mIG1hbGVzIG9yIGZlbWFsZXMgd2hvIGhhZCAqUC4gZmFsY2lwYXJ1bSogY2FzZXMgZHVyaW5nIG9yIGFmdGVyIHRoZSBvdXRicmVhayAocCA9IDAuNTApLgoKIyMjIFdhcyB0aGVyZSBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gdGhlIGFnZXMgb2YgaW5kaXZpZHVhbHMgd2l0aCAqUC4gZmFsY2lwYXJ1bSogY2FzZXMgY2F1c2VkIGJ5IHRoZSAqdmFyKmNvZGUxLCBhIHJlY29tYmluYW50IG9mICp2YXIqY29kZTEgb3IgYSBkaWZmZXJlbnQgKnZhcipjb2RlIGluIDIwMTMsIDIwMTQgYW5kIDIwMTU/CmBgYHtyfQplY3VfZXBpICU+JSBmaWx0ZXIoT3V0YnJlYWtCaW5hcnkgIT0gIk91dGJyZWFrMjAxMyIsICFpcy5uYShBZ2UpICYgIWlzLm5hKFNleCkpICU+JSBncm91cF9ieShPdXRicmVha1JlY29tYmluYW50KSAlPiUgdGFsbHkoKQplY3VfZXBpICU+JSBmaWx0ZXIoT3V0YnJlYWtCaW5hcnkgIT0gIk91dGJyZWFrMjAxMyIsICFpcy5uYShBZ2UpICYgIWlzLm5hKFNleCkpICU+JSBncm91cF9ieShPdXRicmVha1JlY29tYmluYW50KSAlPiUgc3VtbWFyaXplKG1pbiA9IG1pbihBZ2UpLCBtZWQgPSBtZWRpYW4oQWdlKSwgYXZnID0gbWVhbihBZ2UpLCBtYXggPSBtYXgoQWdlKSkgCgplY3VfZXBpICU+JSBmaWx0ZXIoT3V0YnJlYWtCaW5hcnkgIT0gIk91dGJyZWFrMjAxMyIsICFpcy5uYShBZ2UpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gT3V0YnJlYWtSZWNvbWJpbmFudCwgeSA9IEFnZSkpICsgZ2VvbV9ib3hwbG90KCkgKyBnZW9tX3BvaW50KCkgKyBzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gImtydXNrYWwudGVzdCIsIHBhaXJlZCA9IEYpCmBgYApUaGVyZSB3YXMgbm8gc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiB0aGUgYWdlcyBvZiBpbmRpdmlkdWFscyBkdXJpbmcvYWZ0ZXIgdGhlIG91dGJyZWFrIHdpdGggY2xpbmljYWwgZXBpc29kZXMgY2F1c2VkIGJ5IHRoZSBvdXRicmVhayAqdmFyKmNvZGUsIGEgcmVjb21iaW5hbnQgb3IgYSBkaWZmZXJlbnQgKnZhcipjb2RlIChwID0gMC45NSwgS3J1c2thbC1XYWxsaXMgdGVzdCkuIAoKVGhlIHN1bW1hcnkgc3RhdGlzdGljcyBmb3IgdGhlIGFnZXMgb2YgdGhlc2UgaW5kaXZpZHVhbHMgYWZ0ZXIgdGhlIG91dGJyZWFrIGlzOiBgciBrbml0cjo6a2FibGUoZWN1X2VwaSAlPiUgZmlsdGVyKE91dGJyZWFrQmluYXJ5ICE9ICJPdXRicmVhazIwMTMiLCAhaXMubmEoQWdlKSAmICFpcy5uYShTZXgpKSAlPiUgZ3JvdXBfYnkoT3V0YnJlYWtSZWNvbWJpbmFudCkgJT4lIHN1bW1hcml6ZShtaW4gPSBtaW4oQWdlKSwgbWVkID0gbWVkaWFuKEFnZSksIGF2ZyA9IG1lYW4oQWdlKSwgbWF4ID0gbWF4KEFnZSkpKSAlPiUga2FibGVfc3R5bGluZygpYCAKCiMjIyBXYXMgdGhlcmUgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIHRoZSBwcm9wb3J0aW9uIG9mIG1hbGVzIGFuZCBmZW1hbGVzIHdpdGggKlAuIGZhbGNpcGFydW0qIGNhc2VzIGNhdXNlZCBieSB0aGUgKnZhcipjb2RlMSwgYSByZWNvbWJpbmFudCBvZiAqdmFyKmNvZGUxIG9yIGEgZGlmZmVyZW50ICp2YXIqY29kZSBpbiAyMDE0IGFuZCAyMDE1PwpgYGB7cn0KZWN1X2VwaSAlPiUgZmlsdGVyKE91dGJyZWFrQmluYXJ5ICE9ICJPdXRicmVhazIwMTMiLCAhaXMubmEoQWdlKSAmICFpcy5uYShTZXgpKSAlPiUgZ3JvdXBfYnkoT3V0YnJlYWtSZWNvbWJpbmFudCkgJT4lIHRhbGx5KCkKZWN1X2VwaSAlPiUgZmlsdGVyKE91dGJyZWFrQmluYXJ5ICE9ICJPdXRicmVhazIwMTMiLCAhaXMubmEoQWdlKSAmICFpcy5uYShTZXgpKSAlPiUgZ3JvdXBfYnkoT3V0YnJlYWtSZWNvbWJpbmFudCwgU2V4KSAlPiUgdGFsbHkoKQoKeCA8LSBtYXRyaXgoYygzLCA0LCA0LCA3KSwgbnJvdyA9IDIpCnkgPC0gbWF0cml4KGMoMywgNCwgMSwgMiksIG5yb3cgPSAyKQp6IDwtIG1hdHJpeChjKDQsIDcsIDEsIDIpLCBucm93ID0gMikKCmNoaXNxLnRlc3QoeCwgY29ycmVjdCA9IEYpCmNoaXNxLnRlc3QoeSwgY29ycmVjdCA9IEYpCmNoaXNxLnRlc3QoeiwgY29ycmVjdCA9IEYpCgplY3VfZXBpICU+JSBmaWx0ZXIoT3V0YnJlYWtCaW5hcnkgIT0gIk91dGJyZWFrMjAxMyIsICFpcy5uYShBZ2UpICYgIWlzLm5hKFNleCkpICU+JSBncm91cF9ieShPdXRicmVha1JlY29tYmluYW50LCBTZXgpICU+JSB0YWxseSgpICU+JQogIGdncGxvdChhZXMoeCA9IE91dGJyZWFrUmVjb21iaW5hbnQpKSArIGdlb21fYmFyKGFlcyh5ID0gbiwgZmlsbCA9IFNleCksIHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJmaWxsIikgCmBgYAoKYGBge3J9CmVjdV9lcGkgJT4lIGZpbHRlcighaXMubmEoQWdlKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IE91dGJyZWFrQmluYXJ5LCB5ID0gQWdlKSkgKyBnZW9tX2JveHBsb3QoKSArIGdlb21fcG9pbnQoKSArIHN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAid2lsY294LnRlc3QiLCBwYWlyZWQgPSBGKQoKZWN1X2VwaSAlPiUgZmlsdGVyKCFpcy5uYShBZ2UpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gT3V0YnJlYWtCaW5hcnksIHkgPSBBZ2UpKSArIGdlb21fYm94cGxvdCgpICsgZ2VvbV9wb2ludCgpICsgZmFjZXRfd3JhcCh+U2V4KSArIHN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAid2lsY294LnRlc3QiLCBwYWlyZWQgPSBGKQoKZWN1X2VwaSAlPiUgZmlsdGVyKE91dGJyZWFrQmluYXJ5ICE9ICJPdXRicmVhazIwMTMiLCAhaXMubmEoQWdlKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IE91dGJyZWFrUmVjb21iaW5hbnQsIHkgPSBBZ2UpKSArIGdlb21fYm94cGxvdCgpICsgZ2VvbV9wb2ludCgpICsgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJrcnVza2FsLnRlc3QiLCBwYWlyZWQgPSBGKQoKZWN1X2VwaSAlPiUgZmlsdGVyKE91dGJyZWFrQmluYXJ5ICE9ICJPdXRicmVhazIwMTMiLCAhaXMubmEoQWdlKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IE91dGJyZWFrUmVjb21iaW5hbnQsIHkgPSBBZ2UpKSArIGdlb21fYm94cGxvdCgpICsgZ2VvbV9wb2ludCgpICsgc3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJrcnVza2FsLnRlc3QiLCBwYWlyZWQgPSBGKSArIGZhY2V0X3dyYXAoflNleCkKYGBg